diff --git a/mysql-test/r/ndb_partition_error.result b/mysql-test/r/ndb_partition_error.result index 66f623dee13..d86dc382185 100644 --- a/mysql-test/r/ndb_partition_error.result +++ b/mysql-test/r/ndb_partition_error.result @@ -36,3 +36,12 @@ INSERT INTO t1 VALUES (2); UPDATE t1 SET id=5 WHERE id=2; ERROR HY000: Table has no partition for value 5 DROP TABLE t1; +create table t1 (a int,b int, c int) +engine = ndb +partition by list(a) +partitions 2 +(partition x123 values in (11, 12), +partition x234 values in (5, 1)); +insert into t1 values (NULL,1,1); +ERROR HY000: Table has no partition for value NULL +drop table t1; diff --git a/mysql-test/r/partition.result b/mysql-test/r/partition.result index cd333cc5fb4..59e29046d90 100644 --- a/mysql-test/r/partition.result +++ b/mysql-test/r/partition.result @@ -373,4 +373,53 @@ end// call p()// drop procedure p// drop table t1// +create table t1 (a int,b int,c int,key(a,b)) +partition by range (a) +partitions 3 +(partition x1 values less than (0) tablespace ts1, +partition x2 values less than (10) tablespace ts2, +partition x3 values less than maxvalue tablespace ts3); +insert into t1 values (NULL, 1, 1); +insert into t1 values (0, 1, 1); +insert into t1 values (12, 1, 1); +select partition_name, partition_description, table_rows +from information_schema.partitions where table_schema ='test'; +partition_name partition_description table_rows +x1 0 1 +x2 10 1 +x3 MAXVALUE 1 +drop table t1; +create table t1 (a int,b int, c int) +partition by list(a) +partitions 2 +(partition x123 values in (11,12), +partition x234 values in (1 ,NULL, NULL)); +ERROR HY000: Multiple definition of same constant in list partitioning +create table t1 (a int,b int, c int) +partition by list(a) +partitions 2 +(partition x123 values in (11, NULL), +partition x234 values in (1 ,NULL)); +ERROR HY000: Multiple definition of same constant in list partitioning +create table t1 (a int,b int, c int) +partition by list(a) +partitions 2 +(partition x123 values in (11, 12), +partition x234 values in (5, 1)); +insert into t1 values (NULL,1,1); +ERROR HY000: Table has no partition for value NULL +drop table t1; +create table t1 (a int,b int, c int) +partition by list(a) +partitions 2 +(partition x123 values in (11, 12), +partition x234 values in (NULL, 1)); +insert into t1 values (11,1,6); +insert into t1 values (NULL,1,1); +select partition_name, partition_description, table_rows +from information_schema.partitions where table_schema ='test'; +partition_name partition_description table_rows +x123 11,12 1 +x234 NULL,1 1 +drop table t1; End of 5.1 tests diff --git a/mysql-test/r/rpl_ndb_basic.result b/mysql-test/r/rpl_ndb_basic.result index 0fe681622c9..40e3384be3b 100644 --- a/mysql-test/r/rpl_ndb_basic.result +++ b/mysql-test/r/rpl_ndb_basic.result @@ -71,13 +71,47 @@ CREATE TABLE `t1` ( `nid` int(11) NOT NULL default '0', PRIMARY KEY USING HASH (`nid`)) ENGINE=ndbcluster DEFAULT CHARSET=latin1; INSERT INTO t1 VALUES(1,"XYZ1","ABC1"); +**** On Slave **** BEGIN; UPDATE t1 SET `nom`="LOCK" WHERE `nid`=1; set GLOBAL slave_transaction_retries=1; +**** On Master **** UPDATE t1 SET `nom`="DEAD" WHERE `nid`=1; -SHOW SLAVE STATUS; -Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master - 127.0.0.1 root MASTER_PORT 1 master-bin.000001 master-bin.000001 Yes No 146 Error in Write_rows event: error during transaction execution on table test.t1 0 None 0 No +**** On Slave **** +SHOW SLAVE STATUS;; +Slave_IO_State +Master_Host 127.0.0.1 +Master_User root +Master_Port MASTER_PORT +Connect_Retry 1 +Master_Log_File master-bin.000001 +Read_Master_Log_Pos +Relay_Log_File +Relay_Log_Pos +Relay_Master_Log_File master-bin.000001 +Slave_IO_Running Yes +Slave_SQL_Running No +Replicate_Do_DB +Replicate_Ignore_DB +Replicate_Do_Table +Replicate_Ignore_Table +Replicate_Wild_Do_Table +Replicate_Wild_Ignore_Table +Last_Errno 146 +Last_Error Error in Write_rows event: error during transaction execution on table test.t1 +Skip_Counter 0 +Exec_Master_Log_Pos +Relay_Log_Space +Until_Condition None +Until_Log_File +Until_Log_Pos 0 +Master_SSL_Allowed No +Master_SSL_CA_File +Master_SSL_CA_Path +Master_SSL_Cert +Master_SSL_Cipher +Master_SSL_Key +Seconds_Behind_Master set GLOBAL slave_transaction_retries=10; START SLAVE; select * from t1 order by nid; diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index 470ec96a694..9bd7a42e8de 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -25,7 +25,7 @@ rpl_ddl : Bug#15963 SBR does not show "Definer" correctly rpl_ndb_2innodb : Bugs#17400: delete & update of rows in table without pk fails rpl_ndb_2myisam : Bugs#17400: delete & update of rows in table without pk fails rpl_ndb_auto_inc : Bug#17086 -rpl_ndb_basic : Bug#16228 [IN REVIEW] +#rpl_ndb_basic : Bug#16228 [IN REVIEW] rpl_ndb_ddl : Bug#17400: delete & update of rows in table without pk fails rpl_ndb_delete_nowhere : Bug#17400: delete & update of rows in table without pk fails rpl_ndb_innodb2ndb : Bugs#17400: delete & update of rows in table without pk fails diff --git a/mysql-test/t/ndb_partition_error.test b/mysql-test/t/ndb_partition_error.test index c84266b66f7..b2b6017ce7b 100644 --- a/mysql-test/t/ndb_partition_error.test +++ b/mysql-test/t/ndb_partition_error.test @@ -56,3 +56,16 @@ INSERT INTO t1 VALUES (2); --error ER_NO_PARTITION_FOR_GIVEN_VALUE UPDATE t1 SET id=5 WHERE id=2; DROP TABLE t1; + +# +# NULL for LIST partition +# +create table t1 (a int,b int, c int) +engine = ndb +partition by list(a) +partitions 2 +(partition x123 values in (11, 12), + partition x234 values in (5, 1)); +--error 1504 +insert into t1 values (NULL,1,1); +drop table t1; diff --git a/mysql-test/t/partition.test b/mysql-test/t/partition.test index 47c25652ae9..f22edb54756 100644 --- a/mysql-test/t/partition.test +++ b/mysql-test/t/partition.test @@ -483,4 +483,61 @@ drop procedure p// drop table t1// delimiter ;// +# +# Bug #15447 Partitions: NULL is treated as zero +# + +# NULL for RANGE partition +create table t1 (a int,b int,c int,key(a,b)) +partition by range (a) +partitions 3 +(partition x1 values less than (0) tablespace ts1, + partition x2 values less than (10) tablespace ts2, + partition x3 values less than maxvalue tablespace ts3); + +insert into t1 values (NULL, 1, 1); +insert into t1 values (0, 1, 1); +insert into t1 values (12, 1, 1); + +select partition_name, partition_description, table_rows +from information_schema.partitions where table_schema ='test'; +drop table t1; + +# NULL for LIST partition +--error 1473 +create table t1 (a int,b int, c int) +partition by list(a) +partitions 2 +(partition x123 values in (11,12), + partition x234 values in (1 ,NULL, NULL)); + +--error 1473 +create table t1 (a int,b int, c int) +partition by list(a) +partitions 2 +(partition x123 values in (11, NULL), + partition x234 values in (1 ,NULL)); + +create table t1 (a int,b int, c int) +partition by list(a) +partitions 2 +(partition x123 values in (11, 12), + partition x234 values in (5, 1)); +--error 1504 +insert into t1 values (NULL,1,1); +drop table t1; + +create table t1 (a int,b int, c int) +partition by list(a) +partitions 2 +(partition x123 values in (11, 12), + partition x234 values in (NULL, 1)); + +insert into t1 values (11,1,6); +insert into t1 values (NULL,1,1); + +select partition_name, partition_description, table_rows +from information_schema.partitions where table_schema ='test'; +drop table t1; + --echo End of 5.1 tests diff --git a/mysql-test/t/rpl_ndb_basic.test b/mysql-test/t/rpl_ndb_basic.test index 57028464179..bcce0284642 100644 --- a/mysql-test/t/rpl_ndb_basic.test +++ b/mysql-test/t/rpl_ndb_basic.test @@ -98,6 +98,7 @@ INSERT INTO t1 VALUES(1,"XYZ1","ABC1"); # cause a lock on that row on the slave --sync_slave_with_master --connection slave +--echo **** On Slave **** BEGIN; UPDATE t1 SET `nom`="LOCK" WHERE `nid`=1; @@ -107,6 +108,7 @@ set GLOBAL slave_transaction_retries=1; # now do a change to this row on the master # will deadlock on the slave because of lock above --connection master +--echo **** On Master **** UPDATE t1 SET `nom`="DEAD" WHERE `nid`=1; # wait for deadlock to be detected @@ -119,14 +121,14 @@ UPDATE t1 SET `nom`="DEAD" WHERE `nid`=1; # replication should have stopped, since max retries where not enough # verify with show slave status --connection slave +--echo **** On Slave **** --replace_result $MASTER_MYPORT MASTER_PORT --replace_column 1 7 8 9 16 22 23 33 -SHOW SLAVE STATUS; +--query_vertical SHOW SLAVE STATUS; # now set max retries high enough to succeed, and start slave again set GLOBAL slave_transaction_retries=10; START SLAVE; - # wait for deadlock to be detected and retried # should be the same sleep as above for test to be valid --sleep 5 diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index b1836b113e7..6e01330a85e 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -6028,6 +6028,7 @@ void ha_ndbcluster::print_error(int error, myf errflag) { char buf[100]; my_error(ER_NO_PARTITION_FOR_GIVEN_VALUE, MYF(0), + m_part_info->part_expr->null_value ? "NULL" : llstr(m_part_info->part_expr->val_int(), buf)); } else diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index e7a324481db..927b5a4a065 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -5092,6 +5092,7 @@ void ha_partition::print_error(int error, myf errflag) { char buf[100]; my_error(ER_NO_PARTITION_FOR_GIVEN_VALUE, MYF(0), + m_part_info->part_expr->null_value ? "NULL" : llstr(m_part_info->part_expr->val_int(), buf)); } else diff --git a/sql/partition_element.h b/sql/partition_element.h index 8a11c332897..d20715d2408 100644 --- a/sql/partition_element.h +++ b/sql/partition_element.h @@ -51,13 +51,14 @@ public: handlerton *engine_type; enum partition_state part_state; uint16 nodegroup_id; + bool has_null_value; partition_element() : part_max_rows(0), part_min_rows(0), partition_name(NULL), tablespace_name(NULL), range_value(0), part_comment(NULL), data_file_name(NULL), index_file_name(NULL), engine_type(NULL),part_state(PART_NORMAL), - nodegroup_id(UNDEF_NODEGROUP) + nodegroup_id(UNDEF_NODEGROUP), has_null_value(FALSE) { subpartitions.empty(); list_val_list.empty(); diff --git a/sql/partition_info.h b/sql/partition_info.h index c8cb4ae407a..4a00f5c889f 100644 --- a/sql/partition_info.h +++ b/sql/partition_info.h @@ -181,6 +181,9 @@ public: bool linear_hash_ind; bool fixed; bool from_openfrm; + bool has_null_value; + uint has_null_part_id; + partition_info() : get_partition_id(NULL), get_part_partition_id(NULL), @@ -211,7 +214,9 @@ public: list_of_part_fields(FALSE), list_of_subpart_fields(FALSE), linear_hash_ind(FALSE), fixed(FALSE), - from_openfrm(FALSE) + from_openfrm(FALSE), + has_null_value(FALSE), + has_null_part_id(0) { all_fields_in_PF.clear_all(); all_fields_in_PPF.clear_all(); diff --git a/sql/slave.cc b/sql/slave.cc index 39656700e1c..68c4757b735 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -3093,6 +3093,7 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli) else { exec_res= 0; + end_trans(thd, ROLLBACK); /* chance for concurrent connection to get more locks */ safe_sleep(thd, min(rli->trans_retries, MAX_SLAVE_RETRY_PAUSE), (CHECK_KILLED_FUNC)sql_slave_killed, (void*)rli); @@ -3110,8 +3111,16 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli) "the slave_transaction_retries variable.", slave_trans_retries); } - if (!((thd->options & OPTION_BEGIN) && opt_using_transactions)) - rli->trans_retries= 0; // restart from fresh + else if (!((thd->options & OPTION_BEGIN) && opt_using_transactions)) + { + /* + Only reset the retry counter if the event succeeded or + failed with a non-transient error. On a successful event, + the execution will proceed as usual; in the case of a + non-transient error, the slave will stop with an error. + */ + rli->trans_retries= 0; // restart from fresh + } } return exec_res; } diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index c98f8f915b9..257c1988cbd 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -531,6 +531,7 @@ static bool check_list_constants(partition_info *part_info) bool result= TRUE; longlong curr_value, prev_value; partition_element* part_def; + bool found_null= FALSE; List_iterator list_func_it(part_info->partitions); DBUG_ENTER("check_list_constants"); @@ -556,6 +557,17 @@ static bool check_list_constants(partition_info *part_info) do { part_def= list_func_it++; + if (part_def->has_null_value) + { + if (found_null) + { + my_error(ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR, MYF(0)); + goto end; + } + part_info->has_null_value= TRUE; + part_info->has_null_part_id= i; + found_null= TRUE; + } List_iterator list_val_it1(part_def->list_val_list); while (list_val_it1++) no_list_values++; @@ -2041,6 +2053,16 @@ static int add_partition_values(File fptr, partition_info *part_info, err+= add_string(fptr, "VALUES IN "); uint no_items= p_elem->list_val_list.elements; err+= add_begin_parenthesis(fptr); + if (p_elem->has_null_value) + { + err+= add_string(fptr, "NULL"); + if (no_items == 0) + { + err+= add_end_parenthesis(fptr); + goto end; + } + err+= add_comma(fptr); + } i= 0; do { @@ -2051,6 +2073,7 @@ static int add_partition_values(File fptr, partition_info *part_info, } while (++i < no_items); err+= add_end_parenthesis(fptr); } +end: return err + add_space(fptr); } @@ -2631,6 +2654,15 @@ int get_partition_id_list(partition_info *part_info, longlong part_func_value= part_val_int(part_info->part_expr); DBUG_ENTER("get_partition_id_list"); + if (part_info->part_expr->null_value) + { + if (part_info->has_null_value) + { + *part_id= part_info->has_null_part_id; + DBUG_RETURN(0); + } + goto notfound; + } *func_value= part_func_value; while (max_list_index >= min_list_index) { @@ -2741,6 +2773,11 @@ int get_partition_id_range(partition_info *part_info, longlong part_func_value= part_val_int(part_info->part_expr); DBUG_ENTER("get_partition_id_int_range"); + if (part_info->part_expr->null_value) + { + *part_id= 0; + DBUG_RETURN(0); + } while (max_part_id > min_part_id) { loc_part_id= (max_part_id + min_part_id + 1) >> 1; @@ -2814,6 +2851,10 @@ uint32 get_partition_id_range_for_endpoint(partition_info *part_info, uint min_part_id= 0, max_part_id= max_partition, loc_part_id; /* Get the partitioning function value for the endpoint */ longlong part_func_value= part_val_int(part_info->part_expr); + + if (part_info->part_expr->null_value) + DBUG_RETURN(0); + while (max_part_id > min_part_id) { loc_part_id= (max_part_id + min_part_id + 1) >> 1; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 13f880ef228..51c92977a27 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -3832,6 +3832,12 @@ static int get_schema_partitions_record(THD *thd, struct st_table_list *tables, uint no_items= part_elem->list_val_list.elements; tmp_str.length(0); tmp_res.length(0); + if (part_elem->has_null_value) + { + tmp_str.append("NULL"); + if (no_items > 0) + tmp_str.append(","); + } while ((list_value= list_val_it++)) { tmp_res.set(*list_value, cs); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 6c8b52d243c..235e78c6657 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -42,6 +42,12 @@ #include #include +typedef struct p_elem_val +{ + longlong value; + bool null_value; +} part_elem_value; + int yylex(void *yylval, void *yythd); const LEX_STRING null_lex_str={0,0}; @@ -105,6 +111,7 @@ inline Item *is_truth_value(Item *A, bool v1, bool v2) sp_name *spname; struct st_lex *lex; sp_head *sphead; + struct p_elem_val *p_elem_value; } %{ @@ -752,7 +759,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %type ulonglong_num size_number -%type +%type part_bit_expr %type @@ -3781,7 +3788,7 @@ part_func_max: part_range_func: '(' part_bit_expr ')' { - Lex->part_info->curr_part_elem->range_value= $2; + Lex->part_info->curr_part_elem->range_value= $2->value; } ; @@ -3793,12 +3800,12 @@ part_list_func: part_list_item: part_bit_expr { - longlong *value_ptr; - if (!(value_ptr= (longlong*)sql_alloc(sizeof(longlong))) || - ((*value_ptr= $1, FALSE) || - Lex->part_info->curr_part_elem->list_val_list.push_back(value_ptr))) + part_elem_value *value_ptr= $1; + if (!value_ptr->null_value && + Lex->part_info->curr_part_elem-> + list_val_list.push_back((longlong*) &value_ptr->value)) { - mem_alloc_error(sizeof(longlong)); + mem_alloc_error(sizeof(part_elem_value)); YYABORT; } } @@ -3818,6 +3825,15 @@ part_bit_expr: context->table_list= 0; thd->where= "partition function"; + + part_elem_value *value_ptr= + (part_elem_value*)sql_alloc(sizeof(part_elem_value)); + if (!value_ptr) + { + mem_alloc_error(sizeof(part_elem_value)); + YYABORT; + } + if (part_expr->fix_fields(YYTHD, (Item**)0) || ((context->table_list= save_list), FALSE) || (!part_expr->const_item()) || @@ -3827,13 +3843,23 @@ part_bit_expr: YYABORT; } thd->where= save_where; - if (part_expr->result_type() != INT_RESULT) + value_ptr->value= part_expr->val_int(); + if ((value_ptr->null_value= part_expr->null_value)) + { + if (Lex->part_info->curr_part_elem->has_null_value) + { + my_error(ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR, MYF(0)); + YYABORT; + } + Lex->part_info->curr_part_elem->has_null_value= TRUE; + } + else if (part_expr->result_type() != INT_RESULT && + !part_expr->null_value) { yyerror(ER(ER_INCONSISTENT_TYPE_OF_FUNCTIONS_ERROR)); YYABORT; } - item_value= part_expr->val_int(); - $$= item_value; + $$= value_ptr; } ;