MySQL Lists are EOL. Please join:

List:Commits« Previous MessageNext Message »
From:dlenev Date:May 9 2006 12:48pm
Subject:bk commit into 5.0 tree (dlenev:1.2120)
View as plain text  
Below is the list of changes that have just been committed into a local
5.0 repository of dlenev. When dlenev does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet
  1.2120 06/05/09 16:48:23 dlenev@stripped +6 -0
  Merge bk-internal.mysql.com:/home/bk/mysql-5.0-runtime
  into  mysql.com:/home/dlenev/mysql-5.0-bg12472

  mysql-test/t/sp.test
    1.186 06/05/09 16:48:19 dlenev@stripped +23 -23
    Manual merge.

  mysql-test/r/sp.result
    1.198 06/05/09 16:48:19 dlenev@stripped +25 -25
    Manual merge.

  sql/sql_table.cc
    1.305 06/05/09 16:41:39 dlenev@stripped +0 -0
    Auto merged

  sql/sql_insert.cc
    1.188 06/05/09 16:41:39 dlenev@stripped +0 -0
    Auto merged

  sql/sql_base.cc
    1.335 06/05/09 16:41:38 dlenev@stripped +0 -0
    Auto merged

  sql/mysql_priv.h
    1.384 06/05/09 16:41:38 dlenev@stripped +0 -0
    Auto merged

# This is a BitKeeper patch.  What follows are the unified diffs for the
# set of deltas contained in the patch.  The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User:	dlenev
# Host:	jabberwock.site
# Root:	/home/dlenev/mysql-5.0-bg12472/RESYNC

--- 1.383/sql/mysql_priv.h	2006-04-18 19:07:25 +04:00
+++ 1.384/sql/mysql_priv.h	2006-05-09 16:41:38 +04:00
@@ -718,12 +718,6 @@
                         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 @@
 
 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);

--- 1.334/sql/sql_base.cc	2006-04-27 19:20:41 +04:00
+++ 1.335/sql/sql_base.cc	2006-05-09 16:41:38 +04:00
@@ -1160,6 +1160,8 @@
                           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 @@
     }
   }
 
-  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;

--- 1.187/sql/sql_insert.cc	2006-04-11 22:46:20 +04:00
+++ 1.188/sql/sql_insert.cc	2006-05-09 16:41:39 +04:00
@@ -2437,6 +2437,153 @@
   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)
 {

--- 1.304/sql/sql_table.cc	2006-05-01 17:45:56 +04:00
+++ 1.305/sql/sql_table.cc	2006-05-09 16:41:39 +04:00
@@ -1790,105 +1790,6 @@
 
 
 /****************************************************************************
-** Create table from a list of fields and items
-****************************************************************************/
-
-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().
-    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 (! (table= open_table(thd, create_table, thd->mem_root, (bool*) 0,
-                               MYSQL_LOCK_IGNORE_FLUSH)))
-        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);
-}
-
-
-/****************************************************************************
 ** Alter a table definition
 ****************************************************************************/
 

--- 1.197/mysql-test/r/sp.result	2006-04-21 18:54:57 +04:00
+++ 1.198/mysql-test/r/sp.result	2006-05-09 16:48:19 +04:00
@@ -4904,4 +4904,29 @@
 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;

--- 1.185/mysql-test/t/sp.test	2006-04-21 18:54:57 +04:00
+++ 1.186/mysql-test/t/sp.test	2006-05-09 16:48:19 +04:00
@@ -5774,6 +5774,29 @@
 
 
 #
+# 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
 #
 #--disable_warnings
Thread
bk commit into 5.0 tree (dlenev:1.2120)dlenev9 May