3835 Mattias Jonsson 2012-05-19
WL#4443
Fix for CREATE SELECT and delayed locking.
To be consistent with the protocol for locking
and THD::decide_logging_format(), we postpone
locking of target table to after all locks has been
taken on the source tables.
i.e. we create the table in create_select::prepare()
and lock it in create_select::prepare2().
prepare() is called from JOIN::prepare() and
prepare2() from JOIN::exec().
modified:
mysql-test/r/partition_explicit_prune.result
mysql-test/r/partition_locking.result
mysql-test/t/partition_explicit_prune.test
mysql-test/t/partition_locking.test
sql/sql_class.h
sql/sql_insert.cc
sql/sql_select.cc
3834 Mattias Jonsson 2012-05-17
WL#4443
Fix + test for multi UPDATE with BEFORE UPDATE triggers.
modified:
mysql-test/r/partition_locking.result
mysql-test/t/partition_locking.test
sql/sql_update.cc
=== modified file 'mysql-test/r/partition_explicit_prune.result'
--- a/mysql-test/r/partition_explicit_prune.result revid:mattias.jonsson@stripped
+++ b/mysql-test/r/partition_explicit_prune.result revid:mattias.jonsson@stripped
@@ -1923,4 +1923,11 @@ CREATE TEMPORARY TABLE t1 (a INT);
SELECT * FROM t1 PARTITION(pNonexisting);
ERROR HY000: PARTITION () clause on non partitioned table
DROP TEMPORARY TABLE t1;
+#
+# Test CREATE LIKE does not take PARTITION clause
+#
+CREATE TABLE t1 (a INT) PARTITION BY HASH (a) PARTITIONS 3;
+CREATE TABLE t2 LIKE t1 PARTITION (p0, p2);
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'PARTITION (p0, p2)' at line 1
+DROP TABLE t1;
SET @@default_storage_engine = @old_default_storage_engine;
=== modified file 'mysql-test/r/partition_locking.result'
--- a/mysql-test/r/partition_locking.result revid:mattias.jonsson@stripped
+++ b/mysql-test/r/partition_locking.result revid:mattias.jonsson@stripped
@@ -5131,3 +5131,42 @@ DROP TABLE t2;
INSERT INTO t1 VALUES (1);
ERROR 42S02: Table 'test.t2' doesn't exist
DROP TABLE t1;
+CREATE TABLE t1 (a INT) PARTITION BY HASH (a) PARTITIONS 3;
+INSERT INTO t1 VALUES (1), (3), (9), (2), (8), (7);
+FLUSH STATUS;
+CREATE TABLE t2 SELECT * FROM t1 PARTITION (p1, p2);
+SELECT * FROM INFORMATION_SCHEMA.SESSION_STATUS
+WHERE VARIABLE_NAME LIKE 'HANDLER_%' AND VARIABLE_VALUE > 0;
+VARIABLE_NAME VARIABLE_VALUE
+HANDLER_COMMIT 1
+HANDLER_EXTERNAL_LOCK 8
+HANDLER_READ_FIRST 2
+HANDLER_READ_KEY 2
+HANDLER_READ_RND_NEXT 6
+HANDLER_WRITE 21
+# 8 locks (2 tables, 2 partitions, lock/unlock)
+SELECT * FROM t2;
+a
+1
+2
+7
+8
+DROP TABLE t2;
+FLUSH STATUS;
+CREATE TABLE t2 SELECT * FROM t1 WHERE a IN (1, 3, 9);
+SELECT * FROM INFORMATION_SCHEMA.SESSION_STATUS
+WHERE VARIABLE_NAME LIKE 'HANDLER_%' AND VARIABLE_VALUE > 0;
+VARIABLE_NAME VARIABLE_VALUE
+HANDLER_COMMIT 1
+HANDLER_EXTERNAL_LOCK 8
+HANDLER_READ_FIRST 2
+HANDLER_READ_KEY 2
+HANDLER_READ_RND_NEXT 6
+HANDLER_WRITE 20
+# 8 locks (2 tables, 2 partitions, lock/unlock)
+SELECT * FROM t2;
+a
+1
+3
+9
+DROP TABLE t1, t2;
=== modified file 'mysql-test/t/partition_explicit_prune.test'
--- a/mysql-test/t/partition_explicit_prune.test revid:mattias.jonsson@stripped
+++ b/mysql-test/t/partition_explicit_prune.test revid:mattias.jonsson@stripped
@@ -843,4 +843,12 @@ CREATE TEMPORARY TABLE t1 (a INT);
SELECT * FROM t1 PARTITION(pNonexisting);
DROP TEMPORARY TABLE t1;
+--echo #
+--echo # Test CREATE LIKE does not take PARTITION clause
+--echo #
+CREATE TABLE t1 (a INT) PARTITION BY HASH (a) PARTITIONS 3;
+--error ER_PARSE_ERROR
+CREATE TABLE t2 LIKE t1 PARTITION (p0, p2);
+DROP TABLE t1;
+
SET @@default_storage_engine = @old_default_storage_engine;
=== modified file 'mysql-test/t/partition_locking.test'
--- a/mysql-test/t/partition_locking.test revid:mattias.jonsson@stripped
+++ b/mysql-test/t/partition_locking.test revid:mattias.jonsson@stripped
@@ -1975,3 +1975,23 @@ DROP TABLE t2;
--error ER_NO_SUCH_TABLE
INSERT INTO t1 VALUES (1);
DROP TABLE t1;
+
+CREATE TABLE t1 (a INT) PARTITION BY HASH (a) PARTITIONS 3;
+INSERT INTO t1 VALUES (1), (3), (9), (2), (8), (7);
+
+FLUSH STATUS;
+CREATE TABLE t2 SELECT * FROM t1 PARTITION (p1, p2);
+eval $get_handler_status_counts;
+--echo # 8 locks (2 tables, 2 partitions, lock/unlock)
+--sorted_result
+SELECT * FROM t2;
+DROP TABLE t2;
+
+FLUSH STATUS;
+CREATE TABLE t2 SELECT * FROM t1 WHERE a IN (1, 3, 9);
+eval $get_handler_status_counts;
+--echo # 8 locks (2 tables, 2 partitions, lock/unlock)
+--sorted_result
+SELECT * FROM t2;
+
+DROP TABLE t1, t2;
=== modified file 'sql/sql_class.h'
--- a/sql/sql_class.h revid:mattias.jonsson@stripped
+++ b/sql/sql_class.h revid:mattias.jonsson@stripped
@@ -4367,7 +4367,7 @@ public:
// Needed for access from local class MY_HOOKS in prepare(), since thd is proteted.
const THD *get_thd(void) { return thd; }
const HA_CREATE_INFO *get_create_info() { return create_info; };
- int prepare2(void) { return 0; }
+ int prepare2(void);
};
#include <myisam.h>
=== modified file 'sql/sql_insert.cc'
--- a/sql/sql_insert.cc revid:mattias.jonsson@stripped
+++ b/sql/sql_insert.cc revid:mattias.jonsson@stripped
@@ -3897,9 +3897,7 @@ void select_insert::abort_result_set() {
static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
TABLE_LIST *create_table,
Alter_info *alter_info,
- List<Item> *items,
- MYSQL_LOCK **lock,
- TABLEOP_HOOKS *hooks)
+ List<Item> *items)
{
TABLE tmp_table; // Used during 'Create_field()'
TABLE_SHARE share;
@@ -4017,38 +4015,63 @@ static TABLE *create_table_from_items(TH
if (!table) // open failed
DBUG_RETURN(0);
}
+ DBUG_RETURN(table);
+}
- DEBUG_SYNC(thd,"create_table_select_before_lock");
- table->reginfo.lock_type=TL_WRITE;
- hooks->prelock(&table, 1); // Call prelock hooks
- /*
- mysql_lock_tables() below should never fail with request to reopen table
- since it won't wait for the table lock (we have exclusive metadata lock on
- the table) and thus can't get aborted.
- */
- if (! ((*lock)= mysql_lock_tables(thd, &table, 1, 0)) ||
- hooks->postlock(&table, 1))
+/**
+ Create the new table from the selected items.
+
+ @param values List of items to be used as new columns
+ @param u Select
+
+ @return Operation status.
+ @retval 0 Success
+ @retval !=0 Failure
+*/
+
+int
+select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
+{
+ DBUG_ENTER("select_create::prepare");
+
+ unit= u;
+ DBUG_ASSERT(create_table->table == NULL);
+
+ DEBUG_SYNC(thd,"create_table_select_before_check_if_exists");
+
+ if (!(table= create_table_from_items(thd, create_info, create_table,
+ alter_info, &values)))
+ /* abort() deletes table */
+ DBUG_RETURN(-1);
+
+ if (table->s->fields < values.elements)
{
- if (*lock)
- {
- mysql_unlock_tables(thd, *lock);
- *lock= 0;
- }
- drop_open_table(thd, table, create_table->db, create_table->table_name);
- DBUG_RETURN(0);
+ my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), 1L);
+ DBUG_RETURN(-1);
}
- DBUG_RETURN(table);
+ /* First field to copy */
+ field= table->field+table->s->fields - values.elements;
+
+ DBUG_RETURN(0);
}
+/**
+ Lock the newly created table.
+
+ @return Operation status.
+ @retval 0 Success
+ @retval !=0 Failure
+*/
+
int
-select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
+select_create::prepare2()
{
- MYSQL_LOCK *extra_lock= NULL;
- DBUG_ENTER("select_create::prepare");
+ DBUG_ENTER("select_create::prepare2");
+ DEBUG_SYNC(thd,"create_table_select_before_lock");
- TABLEOP_HOOKS *hook_ptr= NULL;
+ MYSQL_LOCK *extra_lock= NULL;
/*
For row-based replication, the CREATE-SELECT statement is written
in two pieces: the first one contain the CREATE TABLE statement
@@ -4108,19 +4131,25 @@ select_create::prepare(List<Item> &value
};
MY_HOOKS hooks(this, create_table, select_tables);
- hook_ptr= &hooks;
-
- unit= u;
- DBUG_ASSERT(create_table->table == NULL);
-
- DEBUG_SYNC(thd,"create_table_select_before_check_if_exists");
-
- if (!(table= create_table_from_items(thd, create_info, create_table,
- alter_info, &values,
- &extra_lock, hook_ptr)))
- /* abort() deletes table */
- DBUG_RETURN(-1);
-
+
+ table->reginfo.lock_type=TL_WRITE;
+ hooks.prelock(&table, 1); // Call prelock hooks
+ /*
+ mysql_lock_tables() below should never fail with request to reopen table
+ since it won't wait for the table lock (we have exclusive metadata lock on
+ the table) and thus can't get aborted.
+ */
+ if (! (extra_lock= mysql_lock_tables(thd, &table, 1, 0)) ||
+ hooks.postlock(&table, 1))
+ {
+ if (extra_lock)
+ {
+ mysql_unlock_tables(thd, extra_lock);
+ extra_lock= 0;
+ }
+ drop_open_table(thd, table, create_table->db, create_table->table_name);
+ DBUG_RETURN(1);
+ }
if (extra_lock)
{
DBUG_ASSERT(m_plock == NULL);
@@ -4132,23 +4161,13 @@ select_create::prepare(List<Item> &value
*m_plock= extra_lock;
}
-
- if (table->s->fields < values.elements)
- {
- my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), 1L);
- DBUG_RETURN(-1);
- }
-
- /* First field to copy */
- field= table->field+table->s->fields - values.elements;
-
/* Mark all fields that are given values */
for (Field **f= field ; *f ; f++)
bitmap_set_bit(table->write_set, (*f)->field_index);
// Set up an empty bitmap of function defaults
if (info.add_function_default_columns(table, table->write_set))
- DBUG_RETURN(TRUE);
+ DBUG_RETURN(1);
table->next_number_field=table->found_next_number_field;
=== modified file 'sql/sql_select.cc'
--- a/sql/sql_select.cc revid:mattias.jonsson@stripped
+++ b/sql/sql_select.cc revid:mattias.jonsson@stripped
@@ -788,7 +788,8 @@ bool JOIN::prepare_result(List<Item> **c
select_lex->handle_derived(thd->lex, &mysql_derived_create))
goto err;
- (void) result->prepare2(); // Currently, this cannot fail.
+ if (result->prepare2())
+ goto err;
if ((select_lex->options & OPTION_SCHEMA_TABLE) &&
get_schema_tables_result(this, PROCESSED_BY_JOIN_EXEC))
No bundle (reason: useless for push emails).
| Thread |
|---|
| • bzr push into mysql-trunk branch (mattias.jonsson:3834 to 3835) WL#4443 | Mattias Jonsson | 20 May |