← Back to team overview

maria-developers team mailing list archive

Please review MDEV-13788 Server crash when issuing bad SQL partition syntax

 

Hello Sergei,

Can you please review a patch for MDEV-13788, for 5.5?

Thanks!
diff --git a/mysql-test/suite/parts/inc/part_alter_values.inc b/mysql-test/suite/parts/inc/part_alter_values.inc
new file mode 100644
index 0000000..f56d81d
--- /dev/null
+++ b/mysql-test/suite/parts/inc/part_alter_values.inc
@@ -0,0 +1,24 @@
+--echo #
+--echo # MDEV-13788 Server crash when issuing bad SQL partition syntax
+--echo #
+
+--eval CREATE TABLE t1 (id int, d date) ENGINE=$engine PARTITION BY RANGE COLUMNS(d) (PARTITION p1 VALUES LESS THAN (MAXVALUE))
+SHOW CREATE TABLE t1;
+--error ER_PARTITION_REQUIRES_VALUES_ERROR
+ALTER TABLE t1 REORGANIZE PARTITION p1 INTO
+(
+  PARTITION p2, /* Notice no values */
+  PARTITION p3 VALUES LESS THAN (MAXVALUE)
+);
+DROP TABLE t1;
+
+
+--eval CREATE TABLE t1 (id int, d date) ENGINE=$engine PARTITION BY LIST (id) (PARTITION p1 VALUES IN (1,2,3))
+SHOW CREATE TABLE t1;
+--error ER_PARTITION_REQUIRES_VALUES_ERROR
+ALTER TABLE t1 REORGANIZE PARTITION p1 INTO
+(
+  PARTITION p2, /* Notice no values */
+  PARTITION p3 VALUES IN (4,5,6)
+);
+DROP TABLE t1;
diff --git a/mysql-test/suite/parts/r/partition_alter_innodb.result b/mysql-test/suite/parts/r/partition_alter_innodb.result
new file mode 100644
index 0000000..4436ba5
--- /dev/null
+++ b/mysql-test/suite/parts/r/partition_alter_innodb.result
@@ -0,0 +1,35 @@
+#
+# MDEV-13788 Server crash when issuing bad SQL partition syntax
+#
+CREATE TABLE t1 (id int, d date) ENGINE=InnoDB PARTITION BY RANGE COLUMNS(d) (PARTITION p1 VALUES LESS THAN (MAXVALUE));
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `id` int(11) DEFAULT NULL,
+  `d` date DEFAULT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+/*!50500 PARTITION BY RANGE  COLUMNS(d)
+(PARTITION p1 VALUES LESS THAN (MAXVALUE) ENGINE = InnoDB) */
+ALTER TABLE t1 REORGANIZE PARTITION p1 INTO
+(
+PARTITION p2, /* Notice no values */
+PARTITION p3 VALUES LESS THAN (MAXVALUE)
+);
+ERROR HY000: Syntax error: RANGE PARTITIONING requires definition of VALUES LESS THAN for each partition
+DROP TABLE t1;
+CREATE TABLE t1 (id int, d date) ENGINE=InnoDB PARTITION BY LIST (id) (PARTITION p1 VALUES IN (1,2,3));
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `id` int(11) DEFAULT NULL,
+  `d` date DEFAULT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (id)
+(PARTITION p1 VALUES IN (1,2,3) ENGINE = InnoDB) */
+ALTER TABLE t1 REORGANIZE PARTITION p1 INTO
+(
+PARTITION p2, /* Notice no values */
+PARTITION p3 VALUES IN (4,5,6)
+);
+ERROR HY000: Syntax error: LIST PARTITIONING requires definition of VALUES IN for each partition
+DROP TABLE t1;
diff --git a/mysql-test/suite/parts/r/partition_alter_maria.result b/mysql-test/suite/parts/r/partition_alter_maria.result
index 6343566..460d20b 100644
--- a/mysql-test/suite/parts/r/partition_alter_maria.result
+++ b/mysql-test/suite/parts/r/partition_alter_maria.result
@@ -16,3 +16,38 @@ select * from t1;
 pk	dt
 1	2017-09-28 15:12:00
 drop table t1;
+#
+# MDEV-13788 Server crash when issuing bad SQL partition syntax
+#
+CREATE TABLE t1 (id int, d date) ENGINE=Aria PARTITION BY RANGE COLUMNS(d) (PARTITION p1 VALUES LESS THAN (MAXVALUE));
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `id` int(11) DEFAULT NULL,
+  `d` date DEFAULT NULL
+) ENGINE=Aria DEFAULT CHARSET=latin1
+/*!50500 PARTITION BY RANGE  COLUMNS(d)
+(PARTITION p1 VALUES LESS THAN (MAXVALUE) ENGINE = Aria) */
+ALTER TABLE t1 REORGANIZE PARTITION p1 INTO
+(
+PARTITION p2, /* Notice no values */
+PARTITION p3 VALUES LESS THAN (MAXVALUE)
+);
+ERROR HY000: Syntax error: RANGE PARTITIONING requires definition of VALUES LESS THAN for each partition
+DROP TABLE t1;
+CREATE TABLE t1 (id int, d date) ENGINE=Aria PARTITION BY LIST (id) (PARTITION p1 VALUES IN (1,2,3));
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `id` int(11) DEFAULT NULL,
+  `d` date DEFAULT NULL
+) ENGINE=Aria DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (id)
+(PARTITION p1 VALUES IN (1,2,3) ENGINE = Aria) */
+ALTER TABLE t1 REORGANIZE PARTITION p1 INTO
+(
+PARTITION p2, /* Notice no values */
+PARTITION p3 VALUES IN (4,5,6)
+);
+ERROR HY000: Syntax error: LIST PARTITIONING requires definition of VALUES IN for each partition
+DROP TABLE t1;
diff --git a/mysql-test/suite/parts/r/partition_alter_myisam.result b/mysql-test/suite/parts/r/partition_alter_myisam.result
new file mode 100644
index 0000000..050e1d9
--- /dev/null
+++ b/mysql-test/suite/parts/r/partition_alter_myisam.result
@@ -0,0 +1,35 @@
+#
+# MDEV-13788 Server crash when issuing bad SQL partition syntax
+#
+CREATE TABLE t1 (id int, d date) ENGINE=MyISAM PARTITION BY RANGE COLUMNS(d) (PARTITION p1 VALUES LESS THAN (MAXVALUE));
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `id` int(11) DEFAULT NULL,
+  `d` date DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+/*!50500 PARTITION BY RANGE  COLUMNS(d)
+(PARTITION p1 VALUES LESS THAN (MAXVALUE) ENGINE = MyISAM) */
+ALTER TABLE t1 REORGANIZE PARTITION p1 INTO
+(
+PARTITION p2, /* Notice no values */
+PARTITION p3 VALUES LESS THAN (MAXVALUE)
+);
+ERROR HY000: Syntax error: RANGE PARTITIONING requires definition of VALUES LESS THAN for each partition
+DROP TABLE t1;
+CREATE TABLE t1 (id int, d date) ENGINE=MyISAM PARTITION BY LIST (id) (PARTITION p1 VALUES IN (1,2,3));
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `id` int(11) DEFAULT NULL,
+  `d` date DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (id)
+(PARTITION p1 VALUES IN (1,2,3) ENGINE = MyISAM) */
+ALTER TABLE t1 REORGANIZE PARTITION p1 INTO
+(
+PARTITION p2, /* Notice no values */
+PARTITION p3 VALUES IN (4,5,6)
+);
+ERROR HY000: Syntax error: LIST PARTITIONING requires definition of VALUES IN for each partition
+DROP TABLE t1;
diff --git a/mysql-test/suite/parts/t/partition_alter_innodb.test b/mysql-test/suite/parts/t/partition_alter_innodb.test
new file mode 100644
index 0000000..451bec0
--- /dev/null
+++ b/mysql-test/suite/parts/t/partition_alter_innodb.test
@@ -0,0 +1,4 @@
+--source include/have_innodb.inc
+--source include/have_partition.inc
+--let $engine=InnoDB
+--source inc/part_alter_values.inc
diff --git a/mysql-test/suite/parts/t/partition_alter_maria.test b/mysql-test/suite/parts/t/partition_alter_maria.test
index db24959..e21f0df 100644
--- a/mysql-test/suite/parts/t/partition_alter_maria.test
+++ b/mysql-test/suite/parts/t/partition_alter_maria.test
@@ -16,3 +16,6 @@ select * from t1;
 alter table t1 drop partition p20181231;
 select * from t1;
 drop table t1;
+
+--let $engine=Aria
+--source inc/part_alter_values.inc
diff --git a/mysql-test/suite/parts/t/partition_alter_myisam.test b/mysql-test/suite/parts/t/partition_alter_myisam.test
new file mode 100644
index 0000000..a53fa33
--- /dev/null
+++ b/mysql-test/suite/parts/t/partition_alter_myisam.test
@@ -0,0 +1,3 @@
+--source include/have_partition.inc
+--let $engine=MyISAM
+--source inc/part_alter_values.inc
diff --git a/sql/partition_info.cc b/sql/partition_info.cc
index 512bf29..740e508 100644
--- a/sql/partition_info.cc
+++ b/sql/partition_info.cc
@@ -2132,6 +2132,24 @@ bool partition_info::fix_column_value_functions(THD *thd,
   DBUG_RETURN(result);
 }
 
+
+bool partition_info::error_if_requires_values() const
+{
+  switch (part_type) {
+  case NOT_A_PARTITION:
+  case HASH_PARTITION:
+    break;
+  case RANGE_PARTITION:
+    my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0), "RANGE", "LESS THAN");
+    return true;
+  case LIST_PARTITION:
+    my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0), "LIST", "IN");
+    return true;
+  }
+  return false;
+}
+
+
 /*
   The parser generates generic data structures, we need to set them up
   as the rest of the code expects to find them. This is in reality part
@@ -2221,6 +2239,8 @@ int partition_info::fix_parser_data(THD *thd)
     part_elem= it++;
     List_iterator<part_elem_value> list_val_it(part_elem->list_val_list);
     num_elements= part_elem->list_val_list.elements;
+    if (!num_elements && error_if_requires_values())
+      DBUG_RETURN(true);
     DBUG_ASSERT(part_type == RANGE_PARTITION ?
                 num_elements == 1U : TRUE);
     for (j= 0; j < num_elements; j++)
diff --git a/sql/partition_info.h b/sql/partition_info.h
index cff941a..779948e 100644
--- a/sql/partition_info.h
+++ b/sql/partition_info.h
@@ -313,6 +313,7 @@ class partition_info : public Sql_alloc
   void set_show_version_string(String *packet);
   void report_part_expr_error(bool use_subpart_expr);
   bool has_same_partitioning(partition_info *new_part_info);
+  bool error_if_requires_values() const;
 private:
   static int list_part_cmp(const void* a, const void* b);
   bool set_up_default_partitions(handler *file, HA_CREATE_INFO *info,
diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc
index ab31a8c..01dcc7c 100644
--- a/sql/sql_partition.cc
+++ b/sql/sql_partition.cc
@@ -4770,16 +4770,11 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info,
             my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0),
                      "LIST", "IN");
           }
-          else if (tab_part_info->part_type == RANGE_PARTITION)
-          {
-            my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0),
-                     "RANGE", "LESS THAN");
-          }
           else
           {
-            DBUG_ASSERT(tab_part_info->part_type == LIST_PARTITION);
-            my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0),
-                     "LIST", "IN");
+            DBUG_ASSERT(tab_part_info->part_type == RANGE_PARTITION ||
+                        tab_part_info->part_type == LIST_PARTITION);
+            (void) tab_part_info->error_if_requires_values();
           }
           goto err;
         }
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 4805cd4..e1c6b5b 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -4679,18 +4679,8 @@ opt_part_values:
             partition_info *part_info= lex->part_info;
             if (! lex->is_partition_management())
             {
-              if (part_info->part_type == RANGE_PARTITION)
-              {
-                my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0),
-                         "RANGE", "LESS THAN");
-                MYSQL_YYABORT;
-              }
-              if (part_info->part_type == LIST_PARTITION)
-              {
-                my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0),
-                         "LIST", "IN");
-                MYSQL_YYABORT;
-              }
+              if (part_info->error_if_requires_values())
+                 MYSQL_YYABORT;
             }
             else
               part_info->part_type= HASH_PARTITION;

Follow ups