use strict;
use warnings;
-our $VERSION = '1.59';
+our $VERSION = '1.62';
our $DEBUG;
$DEBUG = 0 unless defined $DEBUG;
| empty_statement
| <error>
-use : /use/i WORD "$delimiter"
+use : /use/i NAME "$delimiter"
{
$database_name = $item[2];
@table_comments = ();
drop : /drop/i TABLE not_delimiter "$delimiter"
-drop : /drop/i WORD(s) "$delimiter"
+drop : /drop/i NAME(s) "$delimiter"
{ @table_comments = () }
bit:
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.
+ # single-quoted.
- /'(\\.|''|[^\\\'])*'/ |
- /"(\\.|""|[^\\\"])*"/
- # For reference, std sql str: /(?:(?:\')(?:[^\']*(?:(?:\'\')[^\']*)*)(?:\'))//
+ SQSTRING | DQSTRING
nonstring : /[^;\'"]+/
alter_specification : ADD foreign_key_def
{ $return = $item[2] }
-create : CREATE /database/i WORD "$delimiter"
+create : CREATE /database/i NAME "$delimiter"
{ @table_comments = () }
create : CREATE TEMPORARY(?) TABLE opt_if_not_exists(?) table_name '(' create_definition(s /,/) /(,\s*)?\)/ table_option(s?) "$delimiter"
};
}
-view_column_alias : /as/i WORD
+view_column_alias : /as/i NAME
{ $return = $item[2] }
create_definition : constraint
}
-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?)
+field : field_comment(s?) field_name data_type field_qualifier(s?) reference_definition(?) on_update(?) field_comment(s?)
{
my %qualifiers = map { %$_ } @{ $item{'field_qualifier(s?)'} || [] };
if ( my @type_quals = @{ $item{'data_type'}{'qualifiers'} || [] } ) {
? $qualifiers{'not_null'} : 1;
delete $qualifiers{'not_null'};
- my @comments = ( @{ $item[1] }, @{ $item[5] }, @{ $item[8] } );
+ my @comments = ( @{ $item[1] }, (exists $qualifiers{comment} ? delete $qualifiers{comment} : ()) , @{ $item[7] } );
$return = {
supertype => 'field',
}
}
+field_qualifier : /comment/i string
+ {
+ $return = {
+ comment => $item[2],
+ }
+ }
+
reference_definition : /references/i table_name parens_field_list(?) match_type(?) on_delete(?) on_update(?)
{
$return = {
$return = $item[2];
}
|
- /default/i string
+ /default/i VALUE
{
- $item[2] =~ s/^\s*'|'\s*$//g or $item[2] =~ s/^\s*"|"\s*$//g;
$return = $item[2];
}
|
{
$return = $item[2];
}
+ |
+ /default/i NAME # column value, allowed in MariaDB
+ {
+ $return = $item[2];
+ }
auto_inc : /auto_increment/i { 1 }
constraint : primary_key_def
| unique_key_def
| foreign_key_def
+ | check_def
| <error>
+expr : /[^)]* \( [^)]+ \) [^)]*/x # parens, balanced one deep
+ | /[^)]+/
+
+check_def : check_def_begin '(' expr ')'
+ {
+ $return = {
+ supertype => 'constraint',
+ type => 'check',
+ name => $item[1],
+ expression => $item[3],
+ }
+ }
+
+check_def_begin : /constraint/i /check/i NAME
+ { $return = $item[3] }
+ |
+ /constraint/i NAME /check/i
+ { $return = $item[2] }
+ |
+ /constraint/i /check/i
+ { $return = '' }
+
foreign_key_def : foreign_key_def_begin parens_field_list reference_definition
{
$return = {
}
}
-foreign_key_def_begin : /constraint/i /foreign key/i WORD
+foreign_key_def_begin : /constraint/i /foreign key/i NAME
{ $return = $item[3] }
|
/constraint/i NAME /foreign key/i
/constraint/i /foreign key/i
{ $return = '' }
|
- /foreign key/i WORD
+ /foreign key/i NAME
{ $return = $item[2] }
|
/foreign key/i
KEY : /key/i | /index/i
-table_option : /comment/i /=/ /'.*?'/
+table_option : /comment/i /=/ string
{
- my $comment = $item[3];
- $comment =~ s/^'//;
- $comment =~ s/'$//;
- $return = { comment => $comment };
+ $return = { comment => $item[3] };
}
- | /(default )?(charset|character set)/i /\s*=?\s*/ WORD
+ | /(default )?(charset|character set)/i /\s*=?\s*/ NAME
{
$return = { 'CHARACTER SET' => $item[3] };
}
- | /collate/i WORD
+ | /collate/i NAME
{
$return = { 'COLLATE' => $item[2] }
}
{
$return = { $item[1] => $item[4] };
}
- | WORD /\s*=\s*/ MAYBE_QUOTED_WORD
+ | WORD /\s*=\s*/ table_option_value
{
$return = { $item[1] => $item[3] };
}
-MAYBE_QUOTED_WORD: /\w+/
- | /'(\w+)'/
- { $return = $1 }
- | /"(\w+)"/
- { $return = $1 }
+table_option_value : VALUE
+ | NAME
default : /default/i
DOUBLE_QUOTE: '"'
-QUOTED_NAME : BACKTICK /[^`]+/ BACKTICK
- { $item[2] }
- | DOUBLE_QUOTE /[^"]+/ DOUBLE_QUOTE
- { $item[2] }
+SINGLE_QUOTE: "'"
+
+QUOTED_NAME : BQSTRING
+ | SQSTRING
+ | DQSTRING
+
+# MySQL strings, unlike common SQL strings, can have the delmiters
+# escaped either by doubling or by backslashing.
+BQSTRING: BACKTICK <skip: ''> /(?:[^\\`]|``|\\.)*/ BACKTICK
+ { ($return = $item[3]) =~ s/(\\[\\`]|``)/substr($1,1)/ge }
+
+DQSTRING: DOUBLE_QUOTE <skip: ''> /(?:[^\\"]|""|\\.)*/ DOUBLE_QUOTE
+ { ($return = $item[3]) =~ s/(\\[\\"]|"")/substr($1,1)/ge }
+
+SQSTRING: SINGLE_QUOTE <skip: ''> /(?:[^\\']|''|\\.)*/ SINGLE_QUOTE
+ { ($return = $item[3]) =~ s/(\\[\\']|'')/substr($1,1)/ge }
+
NAME: QUOTED_NAME
| /\w+/
-VALUE : /[-+]?\.?\d+(?:[eE]\d+)?/
+VALUE : /[-+]?\d*\.?\d+(?:[eE]\d+)?/
{ $item[1] }
- | /'.*?'/
- {
- # remove leading/trailing quotes
- my $val = $item[1];
- $val =~ s/^['"]|['"]$//g;
- $return = $val;
- }
- | /NULL/
+ | SQSTRING
+ | DQSTRING
+ | /NULL/i
{ 'NULL' }
# always a scalar-ref, so that it is treated as a function and not quoted by consumers
name => $cdata->{'name'},
type => $cdata->{'type'},
fields => $cdata->{'fields'},
+ expression => $cdata->{'expression'},
reference_table => $cdata->{'reference_table'},
reference_fields => $cdata->{'reference_fields'},
match_type => $cdata->{'match_type'} || '',