From: André Walker Date: Thu, 6 Sep 2012 14:34:39 +0000 (-0300) Subject: Make MySQL producer add NULL for every nullable field X-Git-Tag: v0.11013~2 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=dbsrgits%2FSQL-Translator.git;a=commitdiff_plain;h=ad071409cb8f526337abbe025a63aa1e67716165 Make MySQL producer add NULL for every nullable field If the field is nullable, but it isn't followed by the NULL keyword, MySQL can not accept the field definition in some specific cases. --- diff --git a/AUTHORS b/AUTHORS index e8e9683..8e1cff9 100644 --- a/AUTHORS +++ b/AUTHORS @@ -6,6 +6,7 @@ The following people have contributed to the SQLFairy project: - Allen Day - Amiri Barksdale - Anders Nor Berle +- André Walker - Andreas 'ac0v' Specht - Andrew Moore - Andrew Pam diff --git a/Changes b/Changes index 043b4da..1a72142 100644 --- a/Changes +++ b/Changes @@ -1,3 +1,6 @@ +* Make MySQL producer add NULL after every nullable field, conforming to SQL + standard, and avoiding MySQL bugs + # ---------------------------------------------------------- # 0.11012 2012-07-02 # ---------------------------------------------------------- diff --git a/lib/SQL/Translator/Producer/MySQL.pm b/lib/SQL/Translator/Producer/MySQL.pm index 8ec6041..c0e7637 100644 --- a/lib/SQL/Translator/Producer/MySQL.pm +++ b/lib/SQL/Translator/Producer/MySQL.pm @@ -612,7 +612,12 @@ sub create_field } # Null? - $field_def .= ' NOT NULL' unless $field->is_nullable; + if ( $field->is_nullable ) { + $field_def .= ' NULL'; + } + else { + $field_def .= ' NOT NULL'; + } # Default? SQL::Translator::Producer->_apply_default_value( diff --git a/t/30sqlt-new-diff-mysql.t b/t/30sqlt-new-diff-mysql.t index 3bd1653..e295833 100644 --- a/t/30sqlt-new-diff-mysql.t +++ b/t/30sqlt-new-diff-mysql.t @@ -55,7 +55,7 @@ BEGIN; SET foreign_key_checks=0; CREATE TABLE added ( - id integer(11) + id integer(11) NULL ); SET foreign_key_checks=1; @@ -70,19 +70,19 @@ ALTER TABLE person DROP INDEX u_name; ALTER TABLE employee DROP COLUMN job_title; -ALTER TABLE new_name ADD COLUMN new_field integer; +ALTER TABLE new_name ADD COLUMN new_field integer NULL; -ALTER TABLE person ADD COLUMN is_rock_star tinyint(4) DEFAULT 1; +ALTER TABLE person ADD COLUMN is_rock_star tinyint(4) NULL DEFAULT 1; ALTER TABLE person CHANGE COLUMN person_id person_id integer(11) NOT NULL auto_increment; ALTER TABLE person CHANGE COLUMN name name varchar(20) NOT NULL; -ALTER TABLE person CHANGE COLUMN age age integer(11) DEFAULT 18; +ALTER TABLE person CHANGE COLUMN age age integer(11) NULL DEFAULT 18; -ALTER TABLE person CHANGE COLUMN iq iq integer(11) DEFAULT 0; +ALTER TABLE person CHANGE COLUMN iq iq integer(11) NULL DEFAULT 0; -ALTER TABLE person CHANGE COLUMN description physical_description text; +ALTER TABLE person CHANGE COLUMN description physical_description text NULL; ALTER TABLE person ADD UNIQUE INDEX unique_name (name); @@ -117,7 +117,7 @@ BEGIN; SET foreign_key_checks=0; CREATE TABLE added ( - id integer(11) + id integer(11) NULL ); SET foreign_key_checks=1; @@ -125,15 +125,15 @@ SET foreign_key_checks=1; ALTER TABLE employee DROP COLUMN job_title; ALTER TABLE old_name RENAME TO new_name, - ADD COLUMN new_field integer; + ADD COLUMN new_field integer NULL; ALTER TABLE person DROP INDEX UC_age_name, - ADD COLUMN is_rock_star tinyint(4) DEFAULT 1, + ADD COLUMN is_rock_star tinyint(4) NULL DEFAULT 1, CHANGE COLUMN person_id person_id integer(11) NOT NULL auto_increment, CHANGE COLUMN name name varchar(20) NOT NULL, - CHANGE COLUMN age age integer(11) DEFAULT 18, - CHANGE COLUMN iq iq integer(11) DEFAULT 0, - CHANGE COLUMN description physical_description text, + CHANGE COLUMN age age integer(11) NULL DEFAULT 18, + CHANGE COLUMN iq iq integer(11) NULL DEFAULT 0, + CHANGE COLUMN description physical_description text NULL, ADD UNIQUE UC_person_id (person_id), ADD UNIQUE UC_age_name (age, name), ENGINE=InnoDB; @@ -187,7 +187,7 @@ BEGIN; SET foreign_key_checks=0; CREATE TABLE added ( - id integer(11) + id integer(11) NULL ); SET foreign_key_checks=1; @@ -198,12 +198,12 @@ ALTER TABLE employee DROP FOREIGN KEY FK5302D47D93FE702E, ALTER TABLE person DROP INDEX UC_age_name, DROP INDEX u_name, - ADD COLUMN is_rock_star tinyint(4) DEFAULT 1, + ADD COLUMN is_rock_star tinyint(4) NULL DEFAULT 1, CHANGE COLUMN person_id person_id integer(11) NOT NULL auto_increment, CHANGE COLUMN name name varchar(20) NOT NULL, - CHANGE COLUMN age age integer(11) DEFAULT 18, - CHANGE COLUMN iq iq integer(11) DEFAULT 0, - CHANGE COLUMN description physical_description text, + CHANGE COLUMN age age integer(11) NULL DEFAULT 18, + CHANGE COLUMN iq iq integer(11) NULL DEFAULT 0, + CHANGE COLUMN description physical_description text NULL, ADD UNIQUE INDEX unique_name (name), ADD UNIQUE UC_person_id (person_id), ADD UNIQUE UC_age_name (age, name), @@ -257,7 +257,7 @@ BEGIN; ALTER TABLE employee DROP FOREIGN KEY FK5302D47D93FE702E_diff; -ALTER TABLE employee ADD COLUMN new integer, +ALTER TABLE employee ADD COLUMN new integer NULL, ADD CONSTRAINT FK5302D47D93FE702E_diff FOREIGN KEY (employee_id) REFERENCES person (person_id) ON DELETE CASCADE, ADD CONSTRAINT new_constraint FOREIGN KEY (employee_id) REFERENCES patty (fake); diff --git a/t/38-mysql-producer.t b/t/38-mysql-producer.t index 1b72059..45752f6 100644 --- a/t/38-mysql-producer.t +++ b/t/38-mysql-producer.t @@ -187,20 +187,20 @@ my @stmts = ( "DROP TABLE IF EXISTS `thing`", "CREATE TABLE `thing` ( - `id` unsigned int auto_increment, - `name` varchar(32), - `swedish_name` varchar(32) character set swe7, - `description` text character set utf8 collate utf8_general_ci, + `id` unsigned int NULL auto_increment, + `name` varchar(32) NULL, + `swedish_name` varchar(32) character set swe7 NULL, + `description` text character set utf8 collate utf8_general_ci NULL, PRIMARY KEY (`id`), UNIQUE `idx_unique_name` (`name`) ) ENGINE=InnoDB DEFAULT CHARACTER SET latin1 COLLATE latin1_danish_ci", "DROP TABLE IF EXISTS `some`.`thing2`", "CREATE TABLE `some`.`thing2` ( - `id` integer, - `foo` integer, - `foo2` integer, - `bar_set` set('foo', 'bar', 'baz'), + `id` integer NULL, + `foo` integer NULL, + `foo2` integer NULL, + `bar_set` set('foo', 'bar', 'baz') NULL, INDEX `index_1` (`id`), INDEX `really_long_name_bigger_than_64_chars_aaaaaaaaaaaaaaaaa_aed44c47` (`id`), INDEX (`foo`), @@ -212,10 +212,10 @@ my @stmts = ( "DROP TABLE IF EXISTS `some`.`thing3`", "CREATE TABLE `some`.`thing3` ( - `id` integer, - `foo` integer, - `foo2` integer, - `bar_set` set('foo', 'bar', 'baz'), + `id` integer NULL, + `foo` integer NULL, + `foo2` integer NULL, + `bar_set` set('foo', 'bar', 'baz') NULL, INDEX `index_1` (`id`), INDEX `really_long_name_bigger_than_64_chars_aaaaaaaaaaaaaaaaa_aed44c47` (`id`), INDEX (`foo`), @@ -296,7 +296,7 @@ my $field1 = SQL::Translator::Schema::Field->new( name => 'myfield', my $field1_sql = SQL::Translator::Producer::MySQL::create_field($field1); -is($field1_sql, 'myfield VARCHAR(10)', 'Create field works'); +is($field1_sql, 'myfield VARCHAR(10) NULL', 'Create field works'); my $field2 = SQL::Translator::Schema::Field->new( name => 'myfield', table => $table, @@ -314,7 +314,7 @@ is($alter_field, 'ALTER TABLE mytable CHANGE COLUMN myfield myfield VARCHAR(25) my $add_field = SQL::Translator::Producer::MySQL::add_field($field1); -is($add_field, 'ALTER TABLE mytable ADD COLUMN myfield VARCHAR(10)', 'Add field works'); +is($add_field, 'ALTER TABLE mytable ADD COLUMN myfield VARCHAR(10) NULL', 'Add field works'); my $drop_field = SQL::Translator::Producer::MySQL::drop_field($field2); is($drop_field, 'ALTER TABLE mytable DROP COLUMN myfield', 'Drop field works'); @@ -353,7 +353,7 @@ for my $size (keys %$number_sizes) { is( SQL::Translator::Producer::MySQL::create_field($number_field), - "numberfield_$expected $expected($size)", + "numberfield_$expected $expected($size) NULL", "Use $expected for NUMBER types of size $size" ); } @@ -372,68 +372,68 @@ for my $size (qw/255 256 65535 65536/) { is ( SQL::Translator::Producer::MySQL::create_field($varchars->{255}, { mysql_version => 5.000003 }), - 'vch_255 varchar(255)', + 'vch_255 varchar(255) NULL', 'VARCHAR(255) is not substituted with TEXT for Mysql >= 5.0.3' ); is ( SQL::Translator::Producer::MySQL::create_field($varchars->{255}, { mysql_version => 5.0 }), - 'vch_255 varchar(255)', + 'vch_255 varchar(255) NULL', 'VARCHAR(255) is not substituted with TEXT for Mysql < 5.0.3' ); is ( SQL::Translator::Producer::MySQL::create_field($varchars->{255}), - 'vch_255 varchar(255)', + 'vch_255 varchar(255) NULL', 'VARCHAR(255) is not substituted with TEXT when no version specified', ); is ( SQL::Translator::Producer::MySQL::create_field($varchars->{256}, { mysql_version => 5.000003 }), - 'vch_256 varchar(256)', + 'vch_256 varchar(256) NULL', 'VARCHAR(256) is not substituted with TEXT for Mysql >= 5.0.3' ); is ( SQL::Translator::Producer::MySQL::create_field($varchars->{256}, { mysql_version => 5.0 }), - 'vch_256 text', + 'vch_256 text NULL', 'VARCHAR(256) is substituted with TEXT for Mysql < 5.0.3' ); is ( SQL::Translator::Producer::MySQL::create_field($varchars->{256}), - 'vch_256 text', + 'vch_256 text NULL', 'VARCHAR(256) is substituted with TEXT when no version specified', ); is ( SQL::Translator::Producer::MySQL::create_field($varchars->{65535}, { mysql_version => 5.000003 }), - 'vch_65535 varchar(65535)', + 'vch_65535 varchar(65535) NULL', 'VARCHAR(65535) is not substituted with TEXT for Mysql >= 5.0.3' ); is ( SQL::Translator::Producer::MySQL::create_field($varchars->{65535}, { mysql_version => 5.0 }), - 'vch_65535 text', + 'vch_65535 text NULL', 'VARCHAR(65535) is substituted with TEXT for Mysql < 5.0.3' ); is ( SQL::Translator::Producer::MySQL::create_field($varchars->{65535}), - 'vch_65535 text', + 'vch_65535 text NULL', 'VARCHAR(65535) is substituted with TEXT when no version specified', ); is ( SQL::Translator::Producer::MySQL::create_field($varchars->{65536}, { mysql_version => 5.000003 }), - 'vch_65536 text', + 'vch_65536 text NULL', 'VARCHAR(65536) is substituted with TEXT for Mysql >= 5.0.3' ); is ( SQL::Translator::Producer::MySQL::create_field($varchars->{65536}, { mysql_version => 5.0 }), - 'vch_65536 text', + 'vch_65536 text NULL', 'VARCHAR(65536) is substituted with TEXT for Mysql < 5.0.3' ); is ( SQL::Translator::Producer::MySQL::create_field($varchars->{65536}), - 'vch_65536 text', + 'vch_65536 text NULL', 'VARCHAR(65536) is substituted with TEXT when no version specified', ); @@ -516,7 +516,7 @@ EOV is_unique => 0 ); my $sql = SQL::Translator::Producer::MySQL::create_field($field); - is($sql, "my$type $type", "Skip length param for type $type"); + is($sql, "my$type $type NULL", "Skip length param for type $type"); } } @@ -568,7 +568,7 @@ EOV my $add_field = SQL::Translator::Producer::MySQL::add_field($field1, $options); - is($add_field, 'ALTER TABLE `mydb`.`mytable` ADD COLUMN `myfield` VARCHAR(10)', 'Add field works'); + is($add_field, 'ALTER TABLE `mydb`.`mytable` ADD COLUMN `myfield` VARCHAR(10) NULL', 'Add field works'); my $drop_field = SQL::Translator::Producer::MySQL::drop_field($field2, $options); is($drop_field, 'ALTER TABLE `mydb`.`mytable` DROP COLUMN `myfield`', 'Drop field works'); @@ -600,7 +600,7 @@ is($field3_sql, "`myfield` enum('0','1') NOT NULL", 'When no version specified, is( SQL::Translator::Producer::MySQL::create_field($number_field, $options), - "`numberfield_$expected` $expected($size)", + "`numberfield_$expected` $expected($size) NULL", "Use $expected for NUMBER types of size $size" ); } @@ -619,68 +619,68 @@ is($field3_sql, "`myfield` enum('0','1') NOT NULL", 'When no version specified, is ( SQL::Translator::Producer::MySQL::create_field($varchars->{255}, { mysql_version => 5.000003, %$options }), - '`vch_255` varchar(255)', + '`vch_255` varchar(255) NULL', 'VARCHAR(255) is not substituted with TEXT for Mysql >= 5.0.3' ); is ( SQL::Translator::Producer::MySQL::create_field($varchars->{255}, { mysql_version => 5.0, %$options }), - '`vch_255` varchar(255)', + '`vch_255` varchar(255) NULL', 'VARCHAR(255) is not substituted with TEXT for Mysql < 5.0.3' ); is ( SQL::Translator::Producer::MySQL::create_field($varchars->{255}, $options), - '`vch_255` varchar(255)', + '`vch_255` varchar(255) NULL', 'VARCHAR(255) is not substituted with TEXT when no version specified', ); is ( SQL::Translator::Producer::MySQL::create_field($varchars->{256}, { mysql_version => 5.000003, %$options }), - '`vch_256` varchar(256)', + '`vch_256` varchar(256) NULL', 'VARCHAR(256) is not substituted with TEXT for Mysql >= 5.0.3' ); is ( SQL::Translator::Producer::MySQL::create_field($varchars->{256}, { mysql_version => 5.0, %$options }), - '`vch_256` text', + '`vch_256` text NULL', 'VARCHAR(256) is substituted with TEXT for Mysql < 5.0.3' ); is ( SQL::Translator::Producer::MySQL::create_field($varchars->{256}, $options), - '`vch_256` text', + '`vch_256` text NULL', 'VARCHAR(256) is substituted with TEXT when no version specified', ); is ( SQL::Translator::Producer::MySQL::create_field($varchars->{65535}, { mysql_version => 5.000003, %$options }), - '`vch_65535` varchar(65535)', + '`vch_65535` varchar(65535) NULL', 'VARCHAR(65535) is not substituted with TEXT for Mysql >= 5.0.3' ); is ( SQL::Translator::Producer::MySQL::create_field($varchars->{65535}, { mysql_version => 5.0, %$options }), - '`vch_65535` text', + '`vch_65535` text NULL', 'VARCHAR(65535) is substituted with TEXT for Mysql < 5.0.3' ); is ( SQL::Translator::Producer::MySQL::create_field($varchars->{65535}, $options), - '`vch_65535` text', + '`vch_65535` text NULL', 'VARCHAR(65535) is substituted with TEXT when no version specified', ); is ( SQL::Translator::Producer::MySQL::create_field($varchars->{65536}, { mysql_version => 5.000003, %$options }), - '`vch_65536` text', + '`vch_65536` text NULL', 'VARCHAR(65536) is substituted with TEXT for Mysql >= 5.0.3' ); is ( SQL::Translator::Producer::MySQL::create_field($varchars->{65536}, { mysql_version => 5.0, %$options }), - '`vch_65536` text', + '`vch_65536` text NULL', 'VARCHAR(65536) is substituted with TEXT for Mysql < 5.0.3' ); is ( SQL::Translator::Producer::MySQL::create_field($varchars->{65536}, $options), - '`vch_65536` text', + '`vch_65536` text NULL', 'VARCHAR(65536) is substituted with TEXT when no version specified', ); @@ -762,7 +762,7 @@ EOV is_unique => 0 ); my $sql = SQL::Translator::Producer::MySQL::create_field($field, $options); - is($sql, "`my$type` $type", "Skip length param for type $type"); + is($sql, "`my$type` $type NULL", "Skip length param for type $type"); } } }