Skip to content

Commit 777ddd2

Browse files
committed
support generated fields for mysql & fix constraint dropping
1 parent 18be6d1 commit 777ddd2

File tree

4 files changed

+64
-11
lines changed

4 files changed

+64
-11
lines changed

lib/SQL/Translator/Parser/MySQL.pm

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ SQL::Translator::Parser::MySQL - parser for MySQL
1717
The grammar is influenced heavily by Tim Bunce's "mysql2ora" grammar.
1818
1919
Here's the word from the MySQL site
20-
(http://www.mysql.com/doc/en/CREATE_TABLE.html):
20+
(https://dev.mysql.com/doc/refman/en/create-table.html):
2121
2222
CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name [(create_definition,...)]
2323
[table_options] [select_statement]
@@ -27,7 +27,7 @@ Here's the word from the MySQL site
2727
CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name LIKE old_table_name;
2828
2929
create_definition:
30-
col_name type [NOT NULL | NULL] [DEFAULT default_value] [AUTO_INCREMENT]
30+
col_name type [GENERATED ALWAYS] AS (expr) [NOT NULL | NULL] [DEFAULT default_value] [AUTO_INCREMENT]
3131
[PRIMARY KEY] [reference_definition]
3232
or PRIMARY KEY (index_col_name,...)
3333
or KEY [index_name] (index_col_name,...)
@@ -478,7 +478,7 @@ field_comment : /^\s*(?:#|-{2}).*\n/
478478
479479
blank : /\s*/
480480
481-
field : field_comment(s?) field_name data_type field_qualifier(s?) reference_definition(?) on_update(?) field_comment(s?)
481+
field : field_comment(s?) field_name data_type field_generated(s?) field_qualifier(s?) reference_definition(?) on_update(?) field_comment(s?)
482482
{
483483
my %qualifiers = map { %$_ } @{ $item{'field_qualifier(s?)'} || [] };
484484
if ( my @type_quals = @{ $item{'data_type'}{'qualifiers'} || [] } ) {
@@ -497,6 +497,7 @@ field : field_comment(s?) field_name data_type field_qualifier(s?) reference_def
497497
data_type => $item{'data_type'}{'type'},
498498
size => $item{'data_type'}{'size'},
499499
list => $item{'data_type'}{'list'},
500+
generate => $item{'field_generated(s?)'}[0],
500501
null => $null,
501502
constraints => $item{'reference_definition(?)'},
502503
comments => [ @comments ],
@@ -505,6 +506,14 @@ field : field_comment(s?) field_name data_type field_qualifier(s?) reference_def
505506
}
506507
| <error>
507508
509+
field_generated : generated_always(s?) /as/i '(' expr ')' generated_type(s?)
510+
{
511+
$return = {
512+
expr => $item{'expr'},
513+
type => $item{'generated_type(s?)'}[0] || 'VIRTUAL',
514+
}
515+
}
516+
508517
field_qualifier : not_null
509518
{
510519
$return = {
@@ -708,7 +717,12 @@ constraint : primary_key_def
708717
| check_def
709718
| <error>
710719
711-
expr : /[^)]* \( [^)]+ \) [^)]*/x # parens, balanced one deep
720+
generated_always : /generated always/i
721+
722+
generated_type : /stored/i
723+
| /virtual/i
724+
725+
expr : /( [^()]* \( (?: (?> [^()]+ ) | (?1) )* \) ) [^)]*/x # parens, recursive balanced
712726
| /[^)]+/
713727
714728
check_def : check_def_begin '(' expr ')'
@@ -972,7 +986,7 @@ sub parse {
972986

973987
$table->primary_key($field->name) if $fdata->{'is_primary_key'};
974988

975-
for my $qual (qw[ binary unsigned zerofill list collate ], 'character set', 'on update') {
989+
for my $qual (qw[ binary unsigned zerofill list collate ], 'generate', 'character set', 'on update') {
976990
if (my $val = $fdata->{$qual} || $fdata->{ uc $qual }) {
977991
next if ref $val eq 'ARRAY' && !@$val;
978992
$field->extra($qual, $val);

lib/SQL/Translator/Producer/MySQL.pm

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -568,6 +568,7 @@ sub create_field {
568568
my $data_type = $field->data_type;
569569
my @size = $field->size;
570570
my %extra = $field->extra;
571+
my $generate = $extra{'generate'} || {};
571572
my $list = $extra{'list'} || [];
572573
my $commalist = join(', ', map { __PACKAGE__->_quote_string($_) } @$list);
573574
my $charset = $extra{'mysql_charset'};
@@ -624,6 +625,8 @@ sub create_field {
624625
$field_def .= '(' . join(', ', @size) . ')';
625626
}
626627

628+
$field_def .= " GENERATED ALWAYS AS (" . $generate->{expr} . ") " . $generate->{type} if %$generate;
629+
627630
# char sets
628631
$field_def .= " CHARACTER SET $charset" if $charset;
629632
$field_def .= " COLLATE $collate" if $collate;
@@ -723,7 +726,7 @@ sub alter_drop_constraint {
723726
if ($c->type eq PRIMARY_KEY) {
724727
push @out, $c->type;
725728
} else {
726-
push @out, ($c->type eq FOREIGN_KEY ? $c->type : "CONSTRAINT"), $generator->quote($c->name);
729+
push @out, ($c->type eq UNIQUE ? "INDEX" : $c->type), $generator->quote($c->name);
727730
}
728731
return join(' ', @out);
729732
}

t/02mysql-parser.t

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,9 @@ BEGIN {
8787
foo_enabled bit(1) default b'0',
8888
bar_enabled bit(1) default b"1",
8989
long_foo_enabled bit(10) default b'1010101',
90+
g1 int(11) AS (if((1 + 1 = 2),1,NULL)),
91+
g2 int(11) AS (if((1 + 1 = 2),1,(1 + 1))) STORED,
92+
g3 int(11) GENERATED ALWAYS AS (1 + 1) VIRTUAL,
9093
KEY (i1),
9194
UNIQUE (date, i1) USING BTREE,
9295
KEY date_idx (date),
@@ -103,7 +106,7 @@ BEGIN {
103106
is($table->name, 'check', 'Found "check" table');
104107

105108
my @fields = $table->get_fields;
106-
is(scalar @fields, 13, 'Right number of fields (13)');
109+
is(scalar @fields, 16, 'Right number of fields (16)');
107110
my $f1 = shift @fields;
108111
is($f1->name, 'check_id', 'First field name is "check_id"');
109112
is($f1->data_type, 'int', 'Type is "int"');
@@ -218,6 +221,39 @@ BEGIN {
218221
is($f13->default_value, '1010101', 'Default value is 1010101');
219222
is($f13->is_primary_key, 0, 'Field is not PK');
220223

224+
my $f14 = shift @fields;
225+
is($f14->name, 'g1', 'Fifth field name is "g1"');
226+
is($f14->data_type, 'int', 'Type is "int"');
227+
is($f14->size, 11, 'Size is "11"');
228+
is($f14->is_nullable, 1, 'Field can be null');
229+
is($f14->default_value, undef, 'Default value is undefined');
230+
is($f14->is_primary_key, 0, 'Field is not PK');
231+
my %f14extra = $f14->extra;
232+
is($f14extra{'generate'}->{expr}, "if((1 + 1 = 2),1,NULL)", 'Generate expr is "1 + 1"');
233+
is($f14extra{'generate'}->{type}, 'VIRTUAL', 'Generate type is "VIRTUAL"');
234+
235+
my $f15 = shift @fields;
236+
is($f15->name, 'g2', 'Fifth field name is "g2"');
237+
is($f15->data_type, 'int', 'Type is "int"');
238+
is($f15->size, 11, 'Size is "11"');
239+
is($f15->is_nullable, 1, 'Field can be null');
240+
is($f15->default_value, undef, 'Default value is undefined');
241+
is($f15->is_primary_key, 0, 'Field is not PK');
242+
my %f15extra = $f15->extra;
243+
is($f15extra{'generate'}->{expr}, 'if((1 + 1 = 2),1,(1 + 1))', 'Generate expr is "1 + 1"');
244+
is($f15extra{'generate'}->{type}, 'STORED', 'Generate type is "STORED"');
245+
246+
my $f16 = shift @fields;
247+
is($f16->name, 'g3', 'Fifth field name is "g3"');
248+
is($f16->data_type, 'int', 'Type is "int"');
249+
is($f16->size, 11, 'Size is "11"');
250+
is($f16->is_nullable, 1, 'Field can be null');
251+
is($f16->default_value, undef, 'Default value is undefined');
252+
is($f16->is_primary_key, 0, 'Field is not PK');
253+
my %f16extra = $f16->extra;
254+
is($f16extra{'generate'}->{expr}, '1 + 1', 'Generate expr is "1 + 1"');
255+
is($f16extra{'generate'}->{type}, 'VIRTUAL', 'Generate type is "VIRTUAL"');
256+
221257
my @indices = $table->get_indices;
222258
is(scalar @indices, 3, 'Right number of indices (3)');
223259

t/30sqlt-new-diff-mysql.t

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ ALTER TABLE old_name RENAME TO new_name;
6666
6767
ALTER TABLE employee DROP FOREIGN KEY FK5302D47D93FE702E;
6868
69-
ALTER TABLE person DROP CONSTRAINT UC_age_name;
69+
ALTER TABLE person DROP INDEX UC_age_name;
7070
7171
ALTER TABLE person DROP INDEX u_name;
7272
@@ -135,7 +135,7 @@ ALTER TABLE employee DROP COLUMN job_title;
135135
ALTER TABLE old_name RENAME TO new_name,
136136
ADD COLUMN new_field integer NULL;
137137
138-
ALTER TABLE person DROP CONSTRAINT UC_age_name,
138+
ALTER TABLE person DROP INDEX UC_age_name,
139139
ADD COLUMN is_rock_star tinyint(4) NULL DEFAULT 1,
140140
CHANGE COLUMN person_id person_id integer(11) NOT NULL auto_increment,
141141
CHANGE COLUMN name name varchar(20) NOT NULL,
@@ -201,11 +201,11 @@ CREATE TABLE added (
201201
SET foreign_key_checks=1;
202202
203203
ALTER TABLE employee DROP FOREIGN KEY FK5302D47D93FE702E,
204-
DROP CONSTRAINT demo_constraint,
204+
DROP CHECK demo_constraint,
205205
DROP COLUMN job_title,
206206
ADD CONSTRAINT FK5302D47D93FE702E_diff FOREIGN KEY (employee_id) REFERENCES person (person_id);
207207
208-
ALTER TABLE person DROP CONSTRAINT UC_age_name,
208+
ALTER TABLE person DROP INDEX UC_age_name,
209209
DROP INDEX u_name,
210210
ADD COLUMN is_rock_star tinyint(4) NULL DEFAULT 1,
211211
ADD COLUMN value double(8, 2) NULL DEFAULT 0.00,

0 commit comments

Comments
 (0)