From: Date: November 21 2007 6:55pm Subject: bk commit into 5.1 tree (mattiasj:1.2627) BUG#23603 List-Archive: http://lists.mysql.com/commits/38226 X-Bug: 23603 Message-Id: <20071121175538.CCE83219E78@witty.local> Below is the list of changes that have just been committed into a local 5.1 repository of mattiasj. When mattiasj 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@stripped, 2007-11-21 18:55:33+01:00, mattiasj@stripped +11 -0 Bug#23603: Partitions: reoganize means delete Problem was that a user with ALTER priv (and without DROP priv) could do a REORGANIZE PARTITION that could delete rows. Added option "WITH NO DELETE" for use with REORGANIZE PARTITION for non delete operations (do not require DROP priv). Requiring DROP priv if "WITH NO DELETE" is NOT used. mysql-test/r/partition_grant.result@stripped, 2007-11-21 18:55:29+01:00, mattiasj@stripped +57 -0 Bug#23603: Partitions: reoganize means delete test result mysql-test/t/partition_grant.test@stripped, 2007-11-21 18:55:29+01:00, mattiasj@stripped +54 -0 Bug#23603: Partitions: reorganize means delete test case sql/ha_partition.cc@stripped, 2007-11-21 18:55:29+01:00, mattiasj@stripped +24 -6 Bug#23603: Partitions: reorganize means delete Added parameter in change_partitions and copy_partitions to allow alter WITH NO DELETE If delete would occur when "WITH NO DELETE" is given, return error. sql/ha_partition.h@stripped, 2007-11-21 18:55:29+01:00, mattiasj@stripped +6 -2 Bug#23603: Partitions: reorgaize means delete Added a "no delete in reorganize" parameter to change_partitions and copy_partitions sql/handler.h@stripped, 2007-11-21 18:55:29+01:00, mattiasj@stripped +3 -1 Bug#23603: Partitions: reorganize means delete Added a "no delete in reorganize" parameter in change_partitions sql/share/errmsg.txt@stripped, 2007-11-21 18:55:30+01:00, mattiasj@stripped +4 -0 Bug#23603: Partitions: reorgnize means delete Added an error messege if REORGANIZE PARTITION would mean delete (when using the "WITH NO DELETE" option) sql/sql_lex.cc@stripped, 2007-11-21 18:55:29+01:00, mattiasj@stripped +2 -2 Bug#23603: Partitions: reorganize means delete Flags should not be used for equality comparation, only by its bits. sql/sql_lex.h@stripped, 2007-11-21 18:55:29+01:00, mattiasj@stripped +1 -0 Bugs#23603: Partitions: reorganize means delete Added flag for "WITH NO DELETE" part of ALTER...REORGANIZE PARTITION [WITH NO DELETE] sql/sql_parse.cc@stripped, 2007-11-21 18:55:29+01:00, mattiasj@stripped +10 -0 Bug#23603: Partitions: reorganize means delete require DROP privileges for ALTER TABLE ... REORGANIZE PARTITION if not including "WITH NO DELETE" part sql/sql_partition.cc@stripped, 2007-11-21 18:55:30+01:00, mattiasj@stripped +12 -6 Bug#23603: Partitions: reorganize means delete Flags should be compared by bits. Added parameters for change_partitions for use of WITH NO DELETE in reorg partitions sql/sql_yacc.yy@stripped, 2007-11-21 18:55:30+01:00, mattiasj@stripped +10 -2 Bug#23603: Partitions: reorganize means delete Added optional "WITH NO DELETE" for use in REORGANIZE PARTITION diff -Nrup a/mysql-test/r/partition_grant.result b/mysql-test/r/partition_grant.result --- a/mysql-test/r/partition_grant.result 2007-04-04 11:01:44 +02:00 +++ b/mysql-test/r/partition_grant.result 2007-11-21 18:55:29 +01:00 @@ -1,4 +1,61 @@ drop schema if exists mysqltest_1; +CREATE DATABASE mysqltest_1; +USE mysqltest_1; +CREATE TABLE t1 (a INT) +PARTITION BY LIST (a) +(PARTITION p0 VALUES IN (2), +PARTITION p1 VALUES IN (1)); +INSERT INTO t1 VALUES (1); +CREATE USER mysqltest_1@localhost; +GRANT ALTER,SELECT ON mysqltest_1.t1 TO mysqltest_1@localhost; +USE mysqltest_1; +# User mysqltest_1 DB mysqltest_1 (only ALTER and SELECT privs) +ALTER TABLE t1 REORGANIZE PARTITION p1 INTO ( +PARTITION p1 VALUES IN (0) +); +ERROR 42000: DROP command denied to user 'mysqltest_1'@'localhost' for table 't1' +ALTER TABLE t1 REORGANIZE PARTITION p1 INTO ( +PARTITION p1 VALUES IN (1,3) +); +ERROR 42000: DROP command denied to user 'mysqltest_1'@'localhost' for table 't1' +SELECT * FROM t1; +a +1 +ALTER TABLE t1 REORGANIZE PARTITION WITH NO DELETE p1 INTO ( +PARTITION p1 VALUES IN (1,3) +); +SELECT * FROM t1; +a +1 +ALTER TABLE t1 REORGANIZE PARTITION WITH NO DELETE p1 INTO ( +PARTITION p1 VALUES IN (4) +); +ERROR HY000: Impossible ALTER ... WITH NO DELETE. No partition was specified for some existing values. +SELECT * FROM t1; +a +1 +ALTER TABLE t1 DROP PARTITION p1; +ERROR 42000: DROP command denied to user 'mysqltest_1'@'localhost' for table 't1' +DROP TABLE t1; +ERROR 42000: DROP command denied to user 'mysqltest_1'@'localhost' for table 't1' +# User root DB mysqltest_1 (all privs) +SELECT * FROM t1; +a +1 +ALTER TABLE t1 REORGANIZE PARTITION WITH NO DELETE p1 INTO (PARTITION p1 VALUES IN (5)); +ERROR HY000: Impossible ALTER ... WITH NO DELETE. No partition was specified for some existing values. +ALTER TABLE t1 REORGANIZE PARTITION WITH NO DELETE p1 INTO (PARTITION p1 VALUES IN (1,5)); +ALTER TABLE t1 REORGANIZE PARTITION p1 INTO (PARTITION p1 VALUES IN (1,6)); +SELECT * FROM t1; +a +1 +ALTER TABLE t1 REORGANIZE PARTITION p1 INTO (PARTITION p1 VALUES IN (7)); +SELECT * FROM t1; +a +DROP TABLE t1; +USE test; +DROP USER mysqltest_1@localhost; +DROP DATABASE mysqltest_1; create schema mysqltest_1; use mysqltest_1; create table t1 (a int) partition by list (a) (partition p1 values in (1), partition p2 values in (2), partition p3 values in (3)); diff -Nrup a/mysql-test/t/partition_grant.test b/mysql-test/t/partition_grant.test --- a/mysql-test/t/partition_grant.test 2007-06-26 13:15:03 +02:00 +++ b/mysql-test/t/partition_grant.test 2007-11-21 18:55:29 +01:00 @@ -6,6 +6,60 @@ drop schema if exists mysqltest_1; --enable_warnings +# +# Bug #23603: PARTITION ALTER could case delete +# ALTER TABLE t REORGANIZE PARTITION +# requires DROP privileges, if "WITH NO DELETE" is not +# specified. Then it only succeed if it do not delete +# any rows +CREATE DATABASE mysqltest_1; +USE mysqltest_1; +CREATE TABLE t1 (a INT) +PARTITION BY LIST (a) +(PARTITION p0 VALUES IN (2), +PARTITION p1 VALUES IN (1)); +INSERT INTO t1 VALUES (1); +CREATE USER mysqltest_1@localhost; +GRANT ALTER,SELECT ON mysqltest_1.t1 TO mysqltest_1@localhost; +CONNECT (con1,localhost,mysqltest_1,,); +USE mysqltest_1; +-- echo # User mysqltest_1 DB mysqltest_1 (only ALTER and SELECT privs) +--error ER_TABLEACCESS_DENIED_ERROR +ALTER TABLE t1 REORGANIZE PARTITION p1 INTO ( + PARTITION p1 VALUES IN (0) +); +--error ER_TABLEACCESS_DENIED_ERROR +ALTER TABLE t1 REORGANIZE PARTITION p1 INTO ( + PARTITION p1 VALUES IN (1,3) +); +SELECT * FROM t1; +ALTER TABLE t1 REORGANIZE PARTITION WITH NO DELETE p1 INTO ( + PARTITION p1 VALUES IN (1,3) +); +SELECT * FROM t1; +--error ER_PARTITION_ALTER_CAUSES_DELETE +ALTER TABLE t1 REORGANIZE PARTITION WITH NO DELETE p1 INTO ( + PARTITION p1 VALUES IN (4) +); +SELECT * FROM t1; +--error ER_TABLEACCESS_DENIED_ERROR +ALTER TABLE t1 DROP PARTITION p1; +--error ER_TABLEACCESS_DENIED_ERROR +DROP TABLE t1; +connection default; +-- echo # User root DB mysqltest_1 (all privs) +SELECT * FROM t1; +--error ER_PARTITION_ALTER_CAUSES_DELETE +ALTER TABLE t1 REORGANIZE PARTITION WITH NO DELETE p1 INTO (PARTITION p1 VALUES IN (5)); +ALTER TABLE t1 REORGANIZE PARTITION WITH NO DELETE p1 INTO (PARTITION p1 VALUES IN (1,5)); +ALTER TABLE t1 REORGANIZE PARTITION p1 INTO (PARTITION p1 VALUES IN (1,6)); +SELECT * FROM t1; +ALTER TABLE t1 REORGANIZE PARTITION p1 INTO (PARTITION p1 VALUES IN (7)); +SELECT * FROM t1; +DROP TABLE t1; +USE test; +DROP USER mysqltest_1@localhost; +DROP DATABASE mysqltest_1; # # Bug #17139: ALTER TABLE ... DROP PARTITION should require DROP privilege diff -Nrup a/sql/ha_partition.cc b/sql/ha_partition.cc --- a/sql/ha_partition.cc 2007-11-14 14:28:18 +01:00 +++ b/sql/ha_partition.cc 2007-11-21 18:55:29 +01:00 @@ -1212,6 +1212,7 @@ void ha_partition::cleanup_new_partition SYNOPSIS change_partitions() + thd THD object for mem_root use create_info HA_CREATE_INFO object describing all fields and indexes in table path Complete path of db and table name @@ -1219,6 +1220,7 @@ void ha_partition::cleanup_new_partition records are added out: deleted Output parameter where number of deleted records are added + no_del_in_reorg Do not allow delete in REORG PARTITION pack_frm_data Reference to packed frm file pack_frm_len Length of packed frm file @@ -1236,10 +1238,12 @@ void ha_partition::cleanup_new_partition get zero length and a NULL reference here. */ -int ha_partition::change_partitions(HA_CREATE_INFO *create_info, +int ha_partition::change_partitions(THD *thd, + HA_CREATE_INFO *create_info, const char *path, ulonglong *copied, ulonglong *deleted, + bool no_del_in_reorg, const uchar *pack_frm_data __attribute__((unused)), size_t pack_frm_len @@ -1256,7 +1260,6 @@ int ha_partition::change_partitions(HA_C int error= 1; bool first; uint temp_partitions= m_part_info->temp_partitions.elements; - THD *thd= current_thd; DBUG_ENTER("ha_partition::change_partitions"); m_reorged_parts= 0; @@ -1502,7 +1505,7 @@ int ha_partition::change_partitions(HA_C part_elem->part_state= PART_TO_BE_DROPPED; } m_new_file= new_file_array; - DBUG_RETURN(copy_partitions(copied, deleted)); + DBUG_RETURN(copy_partitions(no_del_in_reorg, copied, deleted)); } @@ -1511,6 +1514,7 @@ int ha_partition::change_partitions(HA_C SYNOPSIS copy_partitions() + no_del_in_reorg Do not allow delete in REORG PARTITION out:copied Number of records copied out:deleted Number of records deleted @@ -1524,7 +1528,9 @@ int ha_partition::change_partitions(HA_C partitions. */ -int ha_partition::copy_partitions(ulonglong *copied, ulonglong *deleted) +int ha_partition::copy_partitions(bool no_del_in_reorg, + ulonglong *copied, + ulonglong *deleted) { uint reorg_part= 0; int result= 0; @@ -1562,12 +1568,21 @@ int ha_partition::copy_partitions(ulongl table since it doesn't fit into any partition any longer due to changed partitioning ranges or list values. */ - deleted++; + /* + If ALTER TABLE ... REORGANIZE PARTITION WITH NO DELETE ... + return error that it is impossible to do without delete + */ + if (no_del_in_reorg) + { + result= ER_PARTITION_ALTER_CAUSES_DELETE; + goto error; + } + (*deleted)++; } else { /* Copy record to new handler */ - copied++; + (*copied)++; if ((result= m_new_file[new_part]->write_row(m_rec0))) goto error; } @@ -5379,6 +5394,9 @@ void ha_partition::print_error(int error if (error == HA_ERR_NO_PARTITION_FOUND) m_part_info->print_no_partition_found(table); + else if (error == ER_PARTITION_ALTER_CAUSES_DELETE) + my_error(error, MYF(0)); + else m_file[m_last_part]->print_error(error, errflag); DBUG_VOID_RETURN; diff -Nrup a/sql/ha_partition.h b/sql/ha_partition.h --- a/sql/ha_partition.h 2007-09-24 15:30:28 +02:00 +++ b/sql/ha_partition.h 2007-11-21 18:55:29 +01:00 @@ -195,10 +195,12 @@ public: HA_CREATE_INFO *create_info); virtual void update_create_info(HA_CREATE_INFO *create_info); virtual char *update_table_comment(const char *comment); - virtual int change_partitions(HA_CREATE_INFO *create_info, + virtual int change_partitions(THD *thd, + HA_CREATE_INFO *create_info, const char *path, ulonglong *copied, ulonglong *deleted, + bool no_del_in_reorg, const uchar *pack_frm_data, size_t pack_frm_len); virtual int drop_partitions(const char *path); @@ -212,7 +214,9 @@ public: virtual void change_table_ptr(TABLE *table_arg, TABLE_SHARE *share); private: int prepare_for_delete(); - int copy_partitions(ulonglong *copied, ulonglong *deleted); + int copy_partitions(bool no_del_in_reorg, + ulonglong *copied, + ulonglong *deleted); void cleanup_new_partition(uint part_count); int prepare_new_partition(TABLE *table, HA_CREATE_INFO *create_info, handler *file, const char *part_name, diff -Nrup a/sql/handler.h b/sql/handler.h --- a/sql/handler.h 2007-09-07 15:41:46 +02:00 +++ b/sql/handler.h 2007-11-21 18:55:29 +01:00 @@ -1617,10 +1617,12 @@ public: int action_flag, HA_CREATE_INFO *info) { return FALSE; } - virtual int change_partitions(HA_CREATE_INFO *create_info, + virtual int change_partitions(THD *thd, + HA_CREATE_INFO *create_info, const char *path, ulonglong *copied, ulonglong *deleted, + bool no_del_in_reorg, const uchar *pack_frm_data, size_t pack_frm_len) { return HA_ERR_WRONG_COMMAND; } diff -Nrup a/sql/share/errmsg.txt b/sql/share/errmsg.txt --- a/sql/share/errmsg.txt 2007-11-14 14:28:21 +01:00 +++ b/sql/share/errmsg.txt 2007-11-21 18:55:30 +01:00 @@ -6114,3 +6114,7 @@ ER_TRG_CANT_OPEN_TABLE ER_CANT_CREATE_SROUTINE eng "Cannot create stored routine `%-.64s`. Check warnings" + +ER_PARTITION_ALTER_CAUSES_DELETE + eng "Impossible ALTER ... WITH NO DELETE. No partition was specified for some existing values." + sve "Omöljig ALTER ... WITH NO DELETE, det finns värden som inte har någon partition" diff -Nrup a/sql/sql_lex.cc b/sql/sql_lex.cc --- a/sql/sql_lex.cc 2007-11-10 11:58:37 +01:00 +++ b/sql/sql_lex.cc 2007-11-21 18:55:29 +01:00 @@ -2944,7 +2944,7 @@ bool st_select_lex::add_index_hint (THD bool st_lex::is_partition_management() const { return (sql_command == SQLCOM_ALTER_TABLE && - (alter_info.flags == ALTER_ADD_PARTITION || - alter_info.flags == ALTER_REORGANIZE_PARTITION)); + (alter_info.flags & ALTER_ADD_PARTITION || + alter_info.flags & ALTER_REORGANIZE_PARTITION)); } diff -Nrup a/sql/sql_lex.h b/sql/sql_lex.h --- a/sql/sql_lex.h 2007-11-14 12:25:40 +01:00 +++ b/sql/sql_lex.h 2007-11-21 18:55:29 +01:00 @@ -835,6 +835,7 @@ inline bool st_select_lex_unit::is_union #define ALTER_REPAIR_PARTITION (1L << 24) #define ALTER_REMOVE_PARTITIONING (1L << 25) #define ALTER_FOREIGN_KEY (1L << 26) +#define ALTER_REORG_PART_NO_DELETE (1L << 27) enum enum_alter_table_change_level { diff -Nrup a/sql/sql_parse.cc b/sql/sql_parse.cc --- a/sql/sql_parse.cc 2007-11-15 20:25:41 +01:00 +++ b/sql/sql_parse.cc 2007-11-21 18:55:29 +01:00 @@ -2495,6 +2495,16 @@ end_with_restore_list: */ if (alter_info.flags & (ALTER_DROP_PARTITION | ALTER_RENAME)) priv_needed|= DROP_ACL; + /* + For ALTER TABLE ... REORGANIZE PARTITION ... + We also require DROP priv + For ALTER TABLE ... REORGANIZE PARTITION WITH NO DELETE ... + We do not require DROP priv but returns error in copy_partition + if delete would occur. + */ + if (alter_info.flags & ALTER_REORGANIZE_PARTITION + && !(alter_info.flags & ALTER_REORG_PART_NO_DELETE)) + priv_needed|= DROP_ACL; /* Must be set in the parser */ DBUG_ASSERT(select_lex->db); diff -Nrup a/sql/sql_partition.cc b/sql/sql_partition.cc --- a/sql/sql_partition.cc 2007-11-16 14:07:55 +01:00 +++ b/sql/sql_partition.cc 2007-11-21 18:55:30 +01:00 @@ -4204,7 +4204,7 @@ uint prep_alter_part_table(THD *thd, TAB my_error(ER_PARTITION_MGMT_ON_NONPARTITIONED, MYF(0)); DBUG_RETURN(TRUE); } - if (alter_info->flags == ALTER_TABLE_REORG) + if (alter_info->flags & ALTER_TABLE_REORG) { uint new_part_no, curr_part_no; if (tab_part_info->part_type != HASH_PARTITION || @@ -4734,7 +4734,7 @@ state of p1. tab_part_info->is_auto_partitioned= FALSE; } } - else if (alter_info->flags == ALTER_REORGANIZE_PARTITION) + else if (alter_info->flags & ALTER_REORGANIZE_PARTITION) { /* Reorganise partitions takes a number of partitions that are next @@ -4915,8 +4915,8 @@ the generated partition syntax in a corr } *partition_changed= TRUE; thd->work_part_info= tab_part_info; - if (alter_info->flags == ALTER_ADD_PARTITION || - alter_info->flags == ALTER_REORGANIZE_PARTITION) + if (alter_info->flags & ALTER_ADD_PARTITION || + alter_info->flags & ALTER_REORGANIZE_PARTITION) { if (tab_part_info->use_default_subpartitions && !alt_part_info->use_default_subpartitions) @@ -5090,6 +5090,8 @@ the generated partition syntax in a corr records are added deleted Output parameter where number of deleted records are added + alter_info.flags Flag to copy_partition about ALTER TABLE ... + REORGANIZE PARTITION ... [WITH NO DELETE] */ static bool mysql_change_partitions(ALTER_PARTITION_PARAM_TYPE *lpt) @@ -5100,8 +5102,12 @@ static bool mysql_change_partitions(ALTE DBUG_ENTER("mysql_change_partitions"); build_table_filename(path, sizeof(path), lpt->db, lpt->table_name, "", 0); - if ((error= file->change_partitions(lpt->create_info, path, &lpt->copied, - &lpt->deleted, lpt->pack_frm_data, + if ((error= file->change_partitions(lpt->thd, lpt->create_info, path, + &lpt->copied, + &lpt->deleted, + lpt->alter_info->flags + & ALTER_REORG_PART_NO_DELETE, + lpt->pack_frm_data, lpt->pack_frm_len))) { if (error != ER_OUTOFMEMORY) diff -Nrup a/sql/sql_yacc.yy b/sql/sql_yacc.yy --- a/sql/sql_yacc.yy 2007-11-16 14:07:55 +01:00 +++ b/sql/sql_yacc.yy 2007-11-21 18:55:30 +01:00 @@ -3858,7 +3858,7 @@ opt_part_values: LEX *lex= Lex; if (! lex->is_partition_management()) { - if (Lex->part_info->part_type != LIST_PARTITION) + if (lex->part_info->part_type != LIST_PARTITION) { my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0), "LIST", "IN"); @@ -5541,7 +5541,7 @@ reorg_parts_rule: { Lex->alter_info.flags|= ALTER_TABLE_REORG; } - | alt_part_name_list + | opt_with_no_delete alt_part_name_list { Lex->alter_info.flags|= ALTER_REORGANIZE_PARTITION; } @@ -5549,6 +5549,14 @@ reorg_parts_rule: { LEX *lex= Lex; lex->part_info->no_parts= lex->part_info->partitions.elements; + } + ; + +opt_with_no_delete: + /* empty */ + | WITH NO_SYM DELETE_SYM + { + Lex->alter_info.flags|= ALTER_REORG_PART_NO_DELETE; } ;