-use MooseX::Declare;
role SQL::Translator::Grammar::MySQL {
-
# -------------------------------------------------------------------
# Copyright (C) 2002-2009 SQLFairy Authors
#
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
# 02111-1307 USA
# -------------------------------------------------------------------
-
-method _build_grammar {
-return q!
-{
- my ( $database_name, %tables, $table_order, @table_comments, %views,
- $view_order, %procedures, $proc_order );
- my $delimiter = ';';
-}
-
-#
-# The "eofile" rule makes the parser fail if any "statement" rule
-# fails. Otherwise, the first successful match by a "statement"
-# won't cause the failure needed to know that the parse, as a whole,
-# failed. -ky
-#
-startrule : statement(s) eofile {
- {
- database_name => $database_name,
- tables => \%tables,
- views => \%views,
- procedures => \%procedures,
- }
-}
-
-eofile : /^\Z/
-
-statement : comment
- | use
- | set
- | drop
- | create
- | alter
- | insert
- | delimiter
- | empty_statement
- | <error>
-
-use : /use/i WORD "$delimiter"
- {
- $database_name = $item[2];
- @table_comments = ();
- }
-
-set : /set/i /[^;]+/ "$delimiter"
- { @table_comments = () }
-
-drop : /drop/i TABLE /[^;]+/ "$delimiter"
-
-drop : /drop/i WORD(s) "$delimiter"
- { @table_comments = () }
-
-string :
- # MySQL strings, unlike common SQL strings, can be double-quoted or
- # single-quoted, and you can escape the delmiters by doubling (but only the
- # delimiter) or by backslashing.
-
- /'(\\.|''|[^\\\'])*'/ |
- /"(\\.|""|[^\\\"])*"/
- # For reference, std sql str: /(?:(?:\')(?:[^\']*(?:(?:\'\')[^\']*)*)(?:\'))//
-
-nonstring : /[^;\'"]+/
-
-statement_body : string | nonstring
-
-insert : /insert/i statement_body(s?) "$delimiter"
-
-delimiter : /delimiter/i /[\S]+/
- { $delimiter = $item[2] }
-
-empty_statement : "$delimiter"
-
-alter : ALTER TABLE table_name alter_specification(s /,/) "$delimiter"
- {
- my $table_name = $item{'table_name'};
- die "Cannot ALTER table '$table_name'; it does not exist"
- unless $tables{ $table_name };
- for my $definition ( @{ $item[4] } ) {
- $definition->{'extra'}->{'alter'} = 1;
- push @{ $tables{ $table_name }{'constraints'} }, $definition;
- }
- }
-
-alter_specification : ADD foreign_key_def
- { $return = $item[2] }
-
-create : CREATE /database/i WORD "$delimiter"
- { @table_comments = () }
-
-create : CREATE TEMPORARY(?) TABLE opt_if_not_exists(?) table_name '(' create_definition(s /,/) /(,\s*)?\)/ table_option(s?) "$delimiter"
- {
- my $table_name = $item{'table_name'};
- $tables{ $table_name }{'order'} = ++$table_order;
- $tables{ $table_name }{'name'} = $table_name;
-
- if ( @table_comments ) {
- $tables{ $table_name }{'comments'} = [ @table_comments ];
- @table_comments = ();
+
+ method _build_grammar {
+ return q!
+ {
+ my ( $database_name, %tables, $table_order, @table_comments, %views,
+ $view_order, %procedures, $proc_order );
+ my $delimiter = ';';
}
-
- my $i = 1;
- for my $definition ( @{ $item[7] } ) {
- if ( $definition->{'supertype'} eq 'field' ) {
- my $field_name = $definition->{'name'};
-# $tables{ $table_name }{'columns'}{ $field_name } = { %$definition, order => $i };
- push @{$tables{$table_name}{'columns'}}, $definition;
- $i++;
-
- if ( $definition->{'is_primary_key'} ) {
- push @{ $tables{ $table_name }{'constraints'} },
- {
- type => 'primary_key',
- fields => [ $field_name ],
+
+ #
+ # The "eofile" rule makes the parser fail if any "statement" rule
+ # fails. Otherwise, the first successful match by a "statement"
+ # won't cause the failure needed to know that the parse, as a whole,
+ # failed. -ky
+ #
+ startrule : statement(s) eofile {
+ {
+ database_name => $database_name,
+ tables => \%tables,
+ views => \%views,
+ procedures => \%procedures,
+ }
+ }
+
+ eofile : /^\Z/
+
+ statement : comment
+ | use
+ | set
+ | drop
+ | create
+ | alter
+ | insert
+ | delimiter
+ | empty_statement
+ | <error>
+
+ use : /use/i WORD "$delimiter"
+ {
+ $database_name = $item[2];
+ @table_comments = ();
+ }
+
+ set : /set/i /[^;]+/ "$delimiter"
+ { @table_comments = () }
+
+ drop : /drop/i TABLE /[^;]+/ "$delimiter"
+
+ drop : /drop/i WORD(s) "$delimiter"
+ { @table_comments = () }
+
+ string :
+ # MySQL strings, unlike common SQL strings, can be double-quoted or
+ # single-quoted, and you can escape the delmiters by doubling (but only the
+ # delimiter) or by backslashing.
+
+ /'(\\.|''|[^\\\'])*'/ |
+ /"(\\.|""|[^\\\"])*"/
+ # For reference, std sql str: /(?:(?:\')(?:[^\']*(?:(?:\'\')[^\']*)*)(?:\'))//
+
+ nonstring : /[^;\'"]+/
+
+ statement_body : string | nonstring
+
+ insert : /insert/i statement_body(s?) "$delimiter"
+
+ delimiter : /delimiter/i /[\S]+/
+ { $delimiter = $item[2] }
+
+ empty_statement : "$delimiter"
+
+ alter : ALTER TABLE table_name alter_specification(s /,/) "$delimiter"
+ {
+ my $table_name = $item{'table_name'};
+ die "Cannot ALTER table '$table_name'; it does not exist"
+ unless $tables{ $table_name };
+ for my $definition ( @{ $item[4] } ) {
+ $definition->{'extra'}->{'alter'} = 1;
+ push @{ $tables{ $table_name }{'constraints'} }, $definition;
+ }
+ }
+
+ alter_specification : ADD foreign_key_def
+ { $return = $item[2] }
+
+ create : CREATE /database/i WORD "$delimiter"
+ { @table_comments = () }
+
+ create : CREATE TEMPORARY(?) TABLE opt_if_not_exists(?) table_name '(' create_definition(s /,/) /(,\s*)?\)/ table_option(s?) "$delimiter"
+ {
+ my $table_name = $item{'table_name'};
+ $tables{ $table_name }{'order'} = ++$table_order;
+ $tables{ $table_name }{'table_name'} = $table_name;
+
+ if ( @table_comments ) {
+ $tables{ $table_name }{'comments'} = [ @table_comments ];
+ @table_comments = ();
+ }
+
+ my $i = 1;
+ for my $definition ( @{ $item[7] } ) {
+ if ( $definition->{'supertype'} eq 'field' ) {
+ my $field_name = $definition->{'name'};
+ $tables{ $table_name }{'fields'}{ $field_name } =
+ { %$definition, order => $i };
+ $i++;
+
+ if ( $definition->{'is_primary_key'} ) {
+ push @{ $tables{ $table_name }{'constraints'} },
+ {
+ type => 'primary_key',
+ fields => [ $field_name ],
+ }
+ ;
}
- ;
+ }
+ elsif ( $definition->{'supertype'} eq 'constraint' ) {
+ push @{ $tables{ $table_name }{'constraints'} }, $definition;
+ }
+ elsif ( $definition->{'supertype'} eq 'index' ) {
+ push @{ $tables{ $table_name }{'indices'} }, $definition;
+ }
}
+
+ if ( my @options = @{ $item{'table_option(s?)'} } ) {
+ for my $option ( @options ) {
+ my ( $key, $value ) = each %$option;
+ if ( $key eq 'comment' ) {
+ push @{ $tables{ $table_name }{'comments'} }, $value;
+ }
+ else {
+ push @{ $tables{ $table_name }{'table_options'} }, $option;
+ }
+ }
+ }
+
+ 1;
}
- elsif ( $definition->{'supertype'} eq 'constraint' ) {
- push @{ $tables{ $table_name }{'constraints'} }, $definition;
+
+ opt_if_not_exists : /if not exists/i
+
+ create : CREATE UNIQUE(?) /(index|key)/i index_name /on/i table_name '(' field_name(s /,/) ')' "$delimiter"
+ {
+ @table_comments = ();
+ push @{ $tables{ $item{'table_name'} }{'indices'} },
+ {
+ name => $item[4],
+ type => $item[2][0] ? 'unique' : 'normal',
+ fields => $item[8],
+ }
+ ;
}
- elsif ( $definition->{'supertype'} eq 'index' ) {
- push @{ $tables{ $table_name }{'indices'} }, $definition;
+
+ create : CREATE /trigger/i NAME not_delimiter "$delimiter"
+ {
+ @table_comments = ();
}
- }
-
- if ( my @options = @{ $item{'table_option(s?)'} } ) {
- for my $option ( @options ) {
- my ( $key, $value ) = each %$option;
- if ( $key eq 'comment' ) {
- push @{ $tables{ $table_name }{'comments'} }, $value;
+
+ create : CREATE PROCEDURE NAME not_delimiter "$delimiter"
+ {
+ @table_comments = ();
+ my $func_name = $item[3];
+ my $owner = '';
+ my $sql = "$item[1] $item[2] $item[3] $item[4]";
+
+ $procedures{ $func_name }{'order'} = ++$proc_order;
+ $procedures{ $func_name }{'name'} = $func_name;
+ $procedures{ $func_name }{'owner'} = $owner;
+ $procedures{ $func_name }{'sql'} = $sql;
+ }
+
+ PROCEDURE : /procedure/i
+ | /function/i
+
+ create : CREATE replace(?) algorithm(?) /view/i NAME not_delimiter "$delimiter"
+ {
+ @table_comments = ();
+ my $view_name = $item[5];
+ my $sql = join(q{ }, grep { defined and length } $item[1], $item[2]->[0], $item[3]->[0])
+ . " $item[4] $item[5] $item[6]";
+
+ # Hack to strip database from function calls in SQL
+ $sql =~ s#`\w+`\.(`\w+`\()##g;
+
+ $views{ $view_name }{'order'} = ++$view_order;
+ $views{ $view_name }{'name'} = $view_name;
+ $views{ $view_name }{'sql'} = $sql;
+ }
+
+ replace : /or replace/i
+
+ algorithm : /algorithm/i /=/ WORD
+ {
+ $return = "$item[1]=$item[3]";
+ }
+
+ not_delimiter : /.*?(?=$delimiter)/is
+
+ create_definition : constraint
+ | index
+ | field
+ | comment
+ | <error>
+
+ comment : /^\s*(?:#|-{2}).*\n/
+ {
+ my $comment = $item[1];
+ $comment =~ s/^\s*(#|--)\s*//;
+ $comment =~ s/\s*$//;
+ $return = $comment;
+ }
+
+ comment : /\/\*/ /.*?\*\//s
+ {
+ my $comment = $item[2];
+ $comment = substr($comment, 0, -2);
+ $comment =~ s/^\s*|\s*$//g;
+ $return = $comment;
+ }
+
+ field_comment : /^\s*(?:#|-{2}).*\n/
+ {
+ my $comment = $item[1];
+ $comment =~ s/^\s*(#|--)\s*//;
+ $comment =~ s/\s*$//;
+ $return = $comment;
+ }
+
+
+ field_comment2 : /comment/i /'.*?'/
+ {
+ my $comment = $item[2];
+ $comment =~ s/^'//;
+ $comment =~ s/'$//;
+ $return = $comment;
+ }
+
+ blank : /\s*/
+
+ field : field_comment(s?) field_name data_type field_qualifier(s?) field_comment2(?) reference_definition(?) on_update(?) field_comment(s?)
+ {
+ my %qualifiers = map { %$_ } @{ $item{'field_qualifier(s?)'} || [] };
+ if ( my @type_quals = @{ $item{'data_type'}{'qualifiers'} || [] } ) {
+ $qualifiers{ $_ } = 1 for @type_quals;
+ }
+
+ my $null = defined $qualifiers{'not_null'}
+ ? $qualifiers{'not_null'} : 1;
+ delete $qualifiers{'not_null'};
+
+ my @comments = ( @{ $item[1] }, @{ $item[5] }, @{ $item[8] } );
+
+ $return = {
+ supertype => 'field',
+ name => $item{'field_name'},
+ data_type => $item{'data_type'}{'type'},
+ size => $item{'data_type'}{'size'},
+ list => $item{'data_type'}{'list'},
+ null => $null,
+ constraints => $item{'reference_definition(?)'},
+ comments => [ @comments ],
+ %qualifiers,
+ }
+ }
+ | <error>
+
+ field_qualifier : not_null
+ {
+ $return = {
+ null => $item{'not_null'},
+ }
+ }
+
+ field_qualifier : default_val
+ {
+ $return = {
+ default => $item{'default_val'},
+ }
+ }
+
+ field_qualifier : auto_inc
+ {
+ $return = {
+ is_auto_inc => $item{'auto_inc'},
+ }
+ }
+
+ field_qualifier : primary_key
+ {
+ $return = {
+ is_primary_key => $item{'primary_key'},
+ }
+ }
+
+ field_qualifier : unsigned
+ {
+ $return = {
+ is_unsigned => $item{'unsigned'},
+ }
+ }
+
+ field_qualifier : /character set/i WORD
+ {
+ $return = {
+ 'CHARACTER SET' => $item[2],
+ }
+ }
+
+ field_qualifier : /collate/i WORD
+ {
+ $return = {
+ COLLATE => $item[2],
+ }
+ }
+
+ field_qualifier : /on update/i CURRENT_TIMESTAMP
+ {
+ $return = {
+ 'ON UPDATE' => $item[2],
+ }
+ }
+
+ field_qualifier : /unique/i KEY(?)
+ {
+ $return = {
+ is_unique => 1,
+ }
+ }
+
+ field_qualifier : KEY
+ {
+ $return = {
+ has_index => 1,
+ }
+ }
+
+ reference_definition : /references/i table_name parens_field_list(?) match_type(?) on_delete(?) on_update(?)
+ {
+ $return = {
+ type => 'foreign_key',
+ reference_table => $item[2],
+ reference_fields => $item[3][0],
+ match_type => $item[4][0],
+ on_delete => $item[5][0],
+ on_update => $item[6][0],
+ }
+ }
+
+ match_type : /match full/i { 'full' }
+ |
+ /match partial/i { 'partial' }
+
+ on_delete : /on delete/i reference_option
+ { $item[2] }
+
+ on_update :
+ /on update/i 'CURRENT_TIMESTAMP'
+ { $item[2] }
+ |
+ /on update/i reference_option
+ { $item[2] }
+
+ reference_option: /restrict/i |
+ /cascade/i |
+ /set null/i |
+ /no action/i |
+ /set default/i
+ { $item[1] }
+
+ index : normal_index
+ | fulltext_index
+ | spatial_index
+ | <error>
+
+ table_name : NAME
+
+ field_name : NAME
+
+ index_name : NAME
+
+ data_type : WORD parens_value_list(s?) type_qualifier(s?)
+ {
+ my $type = $item[1];
+ my $size; # field size, applicable only to non-set fields
+ my $list; # set list, applicable only to sets (duh)
+
+ if ( uc($type) =~ /^(SET|ENUM)$/ ) {
+ $size = undef;
+ $list = $item[2][0];
}
else {
- push @{ $tables{ $table_name }{'table_options'} }, $option;
+ $size = $item[2][0];
+ $list = [];
}
+
+
+ $return = {
+ type => $type,
+ size => $size,
+ list => $list,
+ qualifiers => $item[3],
+ }
}
- }
-
- 1;
- }
-
-opt_if_not_exists : /if not exists/i
-
-create : CREATE UNIQUE(?) /(index|key)/i index_name /on/i table_name '(' field_name(s /,/) ')' "$delimiter"
- {
- @table_comments = ();
- push @{ $tables{ $item{'table_name'} }{'indices'} },
+
+ parens_field_list : '(' field_name(s /,/) ')'
+ { $item[2] }
+
+ parens_value_list : '(' VALUE(s /,/) ')'
+ { $item[2] }
+
+ type_qualifier : /(BINARY|UNSIGNED|ZEROFILL)/i
+ { lc $item[1] }
+
+ field_type : WORD
+
+ create_index : /create/i /index/i
+
+ not_null : /not/i /null/i
+ { $return = 0 }
+ |
+ /null/i
+ { $return = 1 }
+
+ unsigned : /unsigned/i { $return = 0 }
+
+ #default_val : /default/i /(?:')?[\s\w\d:.-]*(?:')?/
+ # {
+ # $item[2] =~ s/'//g;
+ # $return = $item[2];
+ # }
+
+ default_val :
+ /default/i 'CURRENT_TIMESTAMP'
{
- name => $item[4],
- type => $item[2][0] ? 'unique' : 'normal',
- fields => $item[8],
+ $return = \$item[2];
}
- ;
- }
-
-create : CREATE /trigger/i NAME not_delimiter "$delimiter"
- {
- @table_comments = ();
- }
-
-create : CREATE PROCEDURE NAME not_delimiter "$delimiter"
- {
- @table_comments = ();
- my $func_name = $item[3];
- my $owner = '';
- my $sql = "$item[1] $item[2] $item[3] $item[4]";
-
- $procedures{ $func_name }{'order'} = ++$proc_order;
- $procedures{ $func_name }{'name'} = $func_name;
- $procedures{ $func_name }{'owner'} = $owner;
- $procedures{ $func_name }{'sql'} = $sql;
- }
-
-PROCEDURE : /procedure/i
- | /function/i
-
-create : CREATE replace(?) algorithm(?) /view/i NAME not_delimiter "$delimiter"
- {
- @table_comments = ();
- my $view_name = $item[5];
- my $sql = join(q{ }, grep { defined and length } $item[1], $item[2]->[0], $item[3]->[0])
- . " $item[4] $item[5] $item[6]";
-
- # Hack to strip database from function calls in SQL
- $sql =~ s#`\w+`\.(`\w+`\()##g;
-
- $views{ $view_name }{'order'} = ++$view_order;
- $views{ $view_name }{'name'} = $view_name;
- $views{ $view_name }{'sql'} = $sql;
- }
-
-replace : /or replace/i
-
-algorithm : /algorithm/i /=/ WORD
- {
- $return = "$item[1]=$item[3]";
- }
-
-not_delimiter : /.*?(?=$delimiter)/is
-
-create_definition : constraint
- | index
- | field
- | comment
- | <error>
-
-comment : /^\s*(?:#|-{2}).*\n/
- {
- my $comment = $item[1];
- $comment =~ s/^\s*(#|--)\s*//;
- $comment =~ s/\s*$//;
- $return = $comment;
- }
-
-comment : /\/\*/ /.*?\*\//s
- {
- my $comment = $item[2];
- $comment = substr($comment, 0, -2);
- $comment =~ s/^\s*|\s*$//g;
- $return = $comment;
- }
-
-field_comment : /^\s*(?:#|-{2}).*\n/
- {
- my $comment = $item[1];
- $comment =~ s/^\s*(#|--)\s*//;
- $comment =~ s/\s*$//;
- $return = $comment;
- }
-
-
-field_comment2 : /comment/i /'.*?'/
- {
- my $comment = $item[2];
- $comment =~ s/^'//;
- $comment =~ s/'$//;
- $return = $comment;
- }
-
-blank : /\s*/
-
-field : field_comment(s?) field_name data_type field_qualifier(s?) field_comment2(?) reference_definition(?) on_update(?) field_comment(s?)
- {
- my %qualifiers = map { %$_ } @{ $item{'field_qualifier(s?)'} || [] };
- if ( my @type_quals = @{ $item{'data_type'}{'qualifiers'} || [] } ) {
- $qualifiers{ $_ } = 1 for @type_quals;
- }
-
- my $null = defined $qualifiers{'not_null'}
- ? $qualifiers{'not_null'} : 1;
- delete $qualifiers{'not_null'};
-
- my @comments = ( @{ $item[1] }, @{ $item[5] }, @{ $item[8] } );
-
- $return = {
- supertype => 'field',
- name => $item{'field_name'},
- data_type => $item{'data_type'}{'type'},
- size => $item{'data_type'}{'size'},
- list => $item{'data_type'}{'list'},
- constraints => $item{'reference_definition(?)'},
- comments => [ @comments ],
- %qualifiers,
- }
- }
- | <error>
-
-field_qualifier : not_null
- {
- $return = {
- is_nullable => $item{'not_null'},
- }
- }
-
-field_qualifier : default_val
- {
- $return = {
- default => $item{'default_val'},
- }
- }
-
-field_qualifier : auto_inc
- {
- $return = {
- is_auto_inc => $item{'auto_inc'},
- }
- }
-
-field_qualifier : primary_key
- {
- $return = {
- is_primary_key => $item{'primary_key'},
- }
- }
-
-field_qualifier : unsigned
- {
- $return = {
- is_unsigned => $item{'unsigned'},
- }
- }
-
-field_qualifier : /character set/i WORD
- {
- $return = {
- 'CHARACTER SET' => $item[2],
- }
- }
-
-field_qualifier : /collate/i WORD
- {
- $return = {
- COLLATE => $item[2],
- }
- }
-
-field_qualifier : /on update/i CURRENT_TIMESTAMP
- {
- $return = {
- 'ON UPDATE' => $item[2],
- }
- }
-
-field_qualifier : /unique/i KEY(?)
- {
- $return = {
- is_unique => 1,
- }
- }
-
-field_qualifier : KEY
- {
- $return = {
- has_index => 1,
- }
- }
-
-reference_definition : /references/i table_name parens_field_list(?) match_type(?) on_delete(?) on_update(?)
- {
- $return = {
- type => 'foreign_key',
- reference_table => $item[2],
- reference_fields => $item[3][0],
- match_type => $item[4][0],
- on_delete => $item[5][0],
- on_update => $item[6][0],
- }
- }
-
-match_type : /match full/i { 'full' }
- |
- /match partial/i { 'partial' }
-
-on_delete : /on delete/i reference_option
- { $item[2] }
-
-on_update :
- /on update/i 'CURRENT_TIMESTAMP'
- { $item[2] }
- |
- /on update/i reference_option
- { $item[2] }
-
-reference_option: /restrict/i |
- /cascade/i |
- /set null/i |
- /no action/i |
- /set default/i
- { $item[1] }
-
-index : normal_index
- | fulltext_index
- | spatial_index
- | <error>
-
-table_name : NAME
-
-field_name : NAME
-
-index_name : NAME
-
-data_type : WORD parens_value_list(s?) type_qualifier(s?)
- {
- my $type = $item[1];
- my $size; # field size, applicable only to non-set fields
- my $list; # set list, applicable only to sets (duh)
-
- if ( uc($type) =~ /^(SET|ENUM)$/ ) {
- $size = undef;
- $list = $item[2][0];
- }
- else {
- $size = $item[2][0][0];
- $list = [];
- }
-
-
- $return = {
- type => $type,
- size => $size,
- list => $list,
- qualifiers => $item[3],
- }
- }
-
-parens_field_list : '(' field_name(s /,/) ')'
- { $item[2] }
-
-parens_value_list : '(' VALUE(s /,/) ')'
- { $item[2] }
-
-type_qualifier : /(BINARY|UNSIGNED|ZEROFILL)/i
- { lc $item[1] }
-
-field_type : WORD
-
-create_index : /create/i /index/i
-
-not_null : /not null/i
- { $return = 0 }
- |
- /null/i
- { $return = 1 }
-
-unsigned : /unsigned/i { $return = 0 }
-
-#default_val : /default/i /(?:')?[\s\w\d:.-]*(?:')?/
-# {
-# $item[2] =~ s/'//g;
-# $return = $item[2];
-# }
-
-default_val :
- /default/i 'CURRENT_TIMESTAMP'
- {
- $return = \$item[2];
- }
- |
- /default/i /'(?:.*?(?:\\'|''))*.*?'|(?:')?[\w\d:.-]*(?:')?/
- {
- $item[2] =~ s/^\s*'|'\s*$//g;
- $return = $item[2];
- }
-
-auto_inc : /auto_increment/i { 1 }
-
-primary_key : /primary/i /key/i { 1 }
-
-constraint : primary_key_def
- | unique_key_def
- | foreign_key_def
- | <error>
-
-foreign_key_def : foreign_key_def_begin parens_field_list reference_definition
- {
- $return = {
- supertype => 'constraint',
- type => 'foreign_key',
- name => $item[1],
- fields => $item[2],
- %{ $item{'reference_definition'} },
- }
- }
-
-foreign_key_def_begin : /constraint/i /foreign key/i WORD
- { $return = $item[3] }
- |
- /constraint/i NAME /foreign key/i
- { $return = $item[2] }
- |
- /constraint/i /foreign key/i
- { $return = '' }
- |
- /foreign key/i WORD
- { $return = $item[2] }
- |
- /foreign key/i
- { $return = '' }
-
-primary_key_def : primary_key index_name(?) '(' name_with_opt_paren(s /,/) ')'
- {
- $return = {
- supertype => 'constraint',
- name => $item{'index_name(?)'}[0],
- type => 'primary_key',
- fields => $item[4],
- };
- }
-
-unique_key_def : UNIQUE KEY(?) index_name(?) '(' name_with_opt_paren(s /,/) ')'
- {
- $return = {
- supertype => 'constraint',
- name => $item{'index_name(?)'}[0],
- type => 'unique',
- fields => $item[5],
- }
- }
-
-normal_index : KEY index_name(?) '(' name_with_opt_paren(s /,/) ')'
- {
- $return = {
- supertype => 'index',
- type => 'normal',
- name => $item{'index_name(?)'}[0],
- fields => $item[4],
- }
- }
-
-fulltext_index : /fulltext/i KEY(?) index_name(?) '(' name_with_opt_paren(s /,/) ')'
- {
- $return = {
- supertype => 'index',
- type => 'fulltext',
- name => $item{'index_name(?)'}[0],
- fields => $item[5],
- }
- }
-
-spatial_index : /spatial/i KEY(?) index_name(?) '(' name_with_opt_paren(s /,/) ')'
- {
- $return = {
- supertype => 'index',
- type => 'spatial',
- name => $item{'index_name(?)'}[0],
- fields => $item[5],
- }
- }
-
-name_with_opt_paren : NAME parens_value_list(s?)
- { $item[2][0] ? "$item[1]($item[2][0][0])" : $item[1] }
-
-UNIQUE : /unique/i
-
-KEY : /key/i | /index/i
-
-table_option : /comment/i /=/ /'.*?'/
- {
- my $comment = $item[3];
- $comment =~ s/^'//;
- $comment =~ s/'$//;
- $return = { comment => $comment };
- }
- | /(default )?(charset|character set)/i /\s*=?\s*/ WORD
- {
- $return = { 'CHARACTER SET' => $item[3] };
- }
- | /collate/i WORD
- {
- $return = { 'COLLATE' => $item[2] }
- }
- | /union/i /\s*=\s*/ '(' table_name(s /,/) ')'
- {
- $return = { $item[1] => $item[4] };
- }
- | WORD /\s*=\s*/ MAYBE_QUOTED_WORD
- {
- $return = { $item[1] => $item[3] };
- }
-
-MAYBE_QUOTED_WORD: /\w+/
- | /'(\w+)'/
- { $return = $1 }
- | /"(\w+)"/
- { $return = $1 }
-
-default : /default/i
-
-ADD : /add/i
-
-ALTER : /alter/i
-
-CREATE : /create/i
-
-TEMPORARY : /temporary/i
-
-TABLE : /table/i
-
-WORD : /\w+/
-
-DIGITS : /\d+/
-
-COMMA : ','
-
-BACKTICK : '`'
-
-DOUBLE_QUOTE: '"'
-
-NAME : BACKTICK /[^`]+/ BACKTICK
- { $item[2] }
- | DOUBLE_QUOTE /[^"]+/ DOUBLE_QUOTE
- { $item[2] }
- | /\w+/
- { $item[1] }
-
-VALUE : /[-+]?\.?\d+(?:[eE]\d+)?/
- { $item[1] }
- | /'.*?'/
- {
- # remove leading/trailing quotes
- my $val = $item[1];
- $val =~ s/^['"]|['"]$//g;
- $return = $val;
+ |
+ /default/i /'(?:.*?(?:\\'|''))*.*?'|(?:')?[\w\d:.-]*(?:')?/
+ {
+ $item[2] =~ s/^\s*'|'\s*$//g;
+ $return = $item[2];
+ }
+
+ auto_inc : /auto_increment/i { 1 }
+
+ primary_key : /primary/i /key/i { 1 }
+
+ constraint : primary_key_def
+ | unique_key_def
+ | foreign_key_def
+ | <error>
+
+ foreign_key_def : foreign_key_def_begin parens_field_list reference_definition
+ {
+ $return = {
+ supertype => 'constraint',
+ type => 'foreign_key',
+ name => $item[1],
+ fields => $item[2],
+ %{ $item{'reference_definition'} },
+ }
+ }
+
+ foreign_key_def_begin : /constraint/i /foreign key/i WORD
+ { $return = $item[3] }
+ |
+ /constraint/i NAME /foreign key/i
+ { $return = $item[2] }
+ |
+ /constraint/i /foreign key/i
+ { $return = '' }
+ |
+ /foreign key/i WORD
+ { $return = $item[2] }
+ |
+ /foreign key/i
+ { $return = '' }
+
+ primary_key_def : primary_key index_name(?) '(' name_with_opt_paren(s /,/) ')'
+ {
+ $return = {
+ supertype => 'constraint',
+ name => $item{'index_name(?)'}[0],
+ type => 'primary_key',
+ fields => $item[4],
+ };
+ }
+
+ unique_key_def : UNIQUE KEY(?) index_name(?) '(' name_with_opt_paren(s /,/) ')'
+ {
+ $return = {
+ supertype => 'constraint',
+ name => $item{'index_name(?)'}[0],
+ type => 'unique',
+ fields => $item[5],
+ }
+ }
+
+ normal_index : KEY index_name(?) '(' name_with_opt_paren(s /,/) ')'
+ {
+ $return = {
+ supertype => 'index',
+ type => 'normal',
+ name => $item{'index_name(?)'}[0],
+ fields => $item[4],
+ }
+ }
+
+ fulltext_index : /fulltext/i KEY(?) index_name(?) '(' name_with_opt_paren(s /,/) ')'
+ {
+ $return = {
+ supertype => 'index',
+ type => 'fulltext',
+ name => $item{'index_name(?)'}[0],
+ fields => $item[5],
+ }
+ }
+
+ spatial_index : /spatial/i KEY(?) index_name(?) '(' name_with_opt_paren(s /,/) ')'
+ {
+ $return = {
+ supertype => 'index',
+ type => 'spatial',
+ name => $item{'index_name(?)'}[0],
+ fields => $item[5],
+ }
+ }
+
+ name_with_opt_paren : NAME parens_value_list(s?)
+ { $item[2][0] ? "$item[1]($item[2][0][0])" : $item[1] }
+
+ UNIQUE : /unique/i
+
+ KEY : /key/i | /index/i
+
+ table_option : /comment/i /=/ /'.*?'/
+ {
+ my $comment = $item[3];
+ $comment =~ s/^'//;
+ $comment =~ s/'$//;
+ $return = { comment => $comment };
+ }
+ | /(default )?(charset|character set)/i /\s*=?\s*/ WORD
+ {
+ $return = { 'CHARACTER SET' => $item[3] };
+ }
+ | /collate/i WORD
+ {
+ $return = { 'COLLATE' => $item[2] }
+ }
+ | /union/i /\s*=\s*/ '(' table_name(s /,/) ')'
+ {
+ $return = { $item[1] => $item[4] };
+ }
+ | WORD /\s*=\s*/ MAYBE_QUOTED_WORD
+ {
+ $return = { $item[1] => $item[3] };
+ }
+
+ MAYBE_QUOTED_WORD: /\w+/
+ | /'(\w+)'/
+ { $return = $1 }
+ | /"(\w+)"/
+ { $return = $1 }
+
+ default : /default/i
+
+ ADD : /add/i
+
+ ALTER : /alter/i
+
+ CREATE : /create/i
+
+ TEMPORARY : /temporary/i
+
+ TABLE : /table/i
+
+ WORD : /\w+/
+
+ DIGITS : /\d+/
+
+ COMMA : ','
+
+ BACKTICK : '`'
+
+ DOUBLE_QUOTE: '"'
+
+ NAME : BACKTICK /[^`]+/ BACKTICK
+ { $item[2] }
+ | DOUBLE_QUOTE /[^"]+/ DOUBLE_QUOTE
+ { $item[2] }
+ | /\w+/
+ { $item[1] }
+
+ VALUE : /[-+]?\.?\d+(?:[eE]\d+)?/
+ { $item[1] }
+ | /'.*?'/
+ {
+ # remove leading/trailing quotes
+ my $val = $item[1];
+ $val =~ s/^['"]|['"]$//g;
+ $return = $val;
+ }
+ | /NULL/
+ { 'NULL' }
+
+ CURRENT_TIMESTAMP : /current_timestamp(\(\))?/i
+ | /now\(\)/i
+ { 'CURRENT_TIMESTAMP' }
+ !;
}
- | /NULL/
- { 'NULL' }
-
-CURRENT_TIMESTAMP : /current_timestamp(\(\))?/i
- | /now\(\)/i
- { 'CURRENT_TIMESTAMP' }
-!;
-}
}