Commit dd68976a authored by unknown's avatar unknown
Browse files

BUG#19145: mysqld crashes if you set the default value of an enum field to NULL

Now test for NULLness the pointers returned from objects created from the
default value. Pushing patch on behalf of cmiller.


mysql-test/r/null.result:
  Add test case
mysql-test/t/null.test:
  Add test case
sql/sql_table.cc:
  No longer blindly dereference pointer of the string representation of the
  values, where "NULL" is NUL. Raise INVALID DEFAULT error messages where
  appropriate.
  
  Note that the -O1 optimization flag made debugging this extremely tricky, with
  misleading results, and that removing it from the Makefile during debugging can
  be invaluable.
parent e92e1dac
Loading
Loading
Loading
Loading
+42 −0
Original line number Diff line number Diff line
@@ -269,3 +269,45 @@ field('str1', null, 'STR1') as c05,
c01	c02	c03	c04	c05	c08	c09
str	str	0	1	2	1	1
set names latin1;
create table bug19145a (e enum('a','b','c')          default 'b' , s set('x', 'y', 'z')          default 'y' ) engine=MyISAM;
create table bug19145b (e enum('a','b','c')          default null, s set('x', 'y', 'z')          default null) engine=MyISAM;
create table bug19145c (e enum('a','b','c') not null default 'b' , s set('x', 'y', 'z') not null default 'y' ) engine=MyISAM;
create table bug19145setnotnulldefaultnull (e enum('a','b','c')          default null, s set('x', 'y', 'z') not null default null) engine=MyISAM;
ERROR 42000: Invalid default value for 's'
create table bug19145enumnotnulldefaultnull (e enum('a','b','c') not null default null, s set('x', 'y', 'z')          default null) engine=MyISAM;
ERROR 42000: Invalid default value for 'e'
alter table bug19145a alter column e set default null;
alter table bug19145a alter column s set default null;
alter table bug19145a add column (i int);
alter table bug19145b alter column e set default null;
alter table bug19145b alter column s set default null;
alter table bug19145b add column (i int);
alter table bug19145c alter column e set default null;
ERROR 42000: Invalid default value for 'e'
alter table bug19145c alter column s set default null;
ERROR 42000: Invalid default value for 's'
alter table bug19145c add column (i int);
show create table bug19145a;
Table	Create Table
bug19145a	CREATE TABLE `bug19145a` (
  `e` enum('a','b','c') default NULL,
  `s` set('x','y','z') default NULL,
  `i` int(11) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
show create table bug19145b;
Table	Create Table
bug19145b	CREATE TABLE `bug19145b` (
  `e` enum('a','b','c') default NULL,
  `s` set('x','y','z') default NULL,
  `i` int(11) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
show create table bug19145c;
Table	Create Table
bug19145c	CREATE TABLE `bug19145c` (
  `e` enum('a','b','c') NOT NULL default 'b',
  `s` set('x','y','z') NOT NULL default 'y',
  `i` int(11) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table bug19145a;
drop table bug19145b;
drop table bug19145c;
+41 −0
Original line number Diff line number Diff line
@@ -187,4 +187,45 @@ select
# Restore charset to the default value.
set names latin1;

#
# Bug#19145: mysqld crashes if you set the default value of an enum field to NULL
#
create table bug19145a (e enum('a','b','c')          default 'b' , s set('x', 'y', 'z')          default 'y' ) engine=MyISAM;
create table bug19145b (e enum('a','b','c')          default null, s set('x', 'y', 'z')          default null) engine=MyISAM;

create table bug19145c (e enum('a','b','c') not null default 'b' , s set('x', 'y', 'z') not null default 'y' ) engine=MyISAM;

# Invalid default value for 's'
--error 1067
create table bug19145setnotnulldefaultnull (e enum('a','b','c')          default null, s set('x', 'y', 'z') not null default null) engine=MyISAM;

# Invalid default value for 'e'
--error 1067
create table bug19145enumnotnulldefaultnull (e enum('a','b','c') not null default null, s set('x', 'y', 'z')          default null) engine=MyISAM;

alter table bug19145a alter column e set default null;
alter table bug19145a alter column s set default null;
alter table bug19145a add column (i int);

alter table bug19145b alter column e set default null;
alter table bug19145b alter column s set default null;
alter table bug19145b add column (i int);

# Invalid default value for 'e'
--error 1067
alter table bug19145c alter column e set default null;

# Invalid default value for 's'
--error 1067
alter table bug19145c alter column s set default null;
alter table bug19145c add column (i int);

show create table bug19145a;
show create table bug19145b;
show create table bug19145c;

drop table bug19145a;
drop table bug19145b;
drop table bug19145c;

# End of 4.1 tests
+39 −10
Original line number Diff line number Diff line
@@ -601,7 +601,7 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
        if (need_to_change_arena)
          thd->restore_backup_item_arena(thd->current_arena, &backup_arena);

        if (! sql_field->def)
        if (sql_field->def == NULL)
        {
          /* Could not convert */
          my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name);
@@ -611,15 +611,30 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,

      if (sql_field->sql_type == FIELD_TYPE_SET)
      {
        if (sql_field->def)
        if (sql_field->def != NULL)
        {
          char *not_used;
          uint not_used2;
          bool not_found= 0;
          String str, *def= sql_field->def->val_str(&str);
          def->length(cs->cset->lengthsp(cs, def->ptr(), def->length()));
          if (def == NULL) /* SQL "NULL" maps to NULL */
          {
            if ((sql_field->flags & NOT_NULL_FLAG) != 0)
            {
              my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name);
              DBUG_RETURN(-1);
            }

            /* else, NULL is an allowed value */
            (void) find_set(interval, NULL, 0,
                            cs, &not_used, &not_used2, &not_found);
          }
          else /* not NULL */
          {
            (void) find_set(interval, def->ptr(), def->length(),
                            cs, &not_used, &not_used2, &not_found);
          }

          if (not_found)
          {
            my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name);
@@ -631,16 +646,30 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
      }
      else  /* FIELD_TYPE_ENUM */
      {
        if (sql_field->def)
        DBUG_ASSERT(sql_field->sql_type == FIELD_TYPE_ENUM);
        if (sql_field->def != NULL)
        {
          String str, *def= sql_field->def->val_str(&str);
          if (def == NULL) /* SQL "NULL" maps to NULL */
          {
            if ((sql_field->flags & NOT_NULL_FLAG) != 0)
            {
              my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name);
              DBUG_RETURN(-1);
            }

            /* else, the defaults yield the correct length for NULLs. */
          } 
          else /* not NULL */
          {
            def->length(cs->cset->lengthsp(cs, def->ptr(), def->length()));
          if (!find_type2(interval, def->ptr(), def->length(), cs))
            if (find_type2(interval, def->ptr(), def->length(), cs) == 0) /* not found */
            {
              my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name);
              DBUG_RETURN(-1);
            }
          }
        }
        calculate_interval_lengths(cs, interval, &sql_field->length, &dummy);
      }
      set_if_smaller(sql_field->length, MAX_FIELD_WIDTH-1);