| 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;
- }
+field_comment2 : /comment/i SQSTRING
+ { $return = $item[2] }
blank : /\s*/
$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];
}
|
}
}
-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
SINGLE_QUOTE: "'"
-QUOTED_NAME : BACKTICK /[^`]+/ BACKTICK
- { $item[2] }
- | DOUBLE_QUOTE /[^"]+/ DOUBLE_QUOTE
- { $item[2] }
- | SINGLE_QUOTE /[^']+/ SINGLE_QUOTE
- { $item[2] }
+QUOTED_NAME : BQSTRING
+ | SQSTRING
+ | DQSTRING
+
+# MySQL strings, unlike common SQL strings, can have the delmiters
+# escaped either by doubling or by backslashing.
+BQSTRING: BACKTICK /(?:[^\\`]|``|\\.)*/ BACKTICK
+ { ($return = $item[2]) =~ s/(\\[\\`]|``)/substr($1,1)/ge }
+
+DQSTRING: DOUBLE_QUOTE /(?:[^\\"]|""|\\.)*/ DOUBLE_QUOTE
+ { ($return = $item[2]) =~ s/(\\[\\"]|"")/substr($1,1)/ge }
+
+SQSTRING: SINGLE_QUOTE /(?:[^\\']|''|\\.)*/ SINGLE_QUOTE
+ { ($return = $item[2]) =~ s/(\\[\\']|'')/substr($1,1)/ge }
+
NAME: QUOTED_NAME
| /\w+/
-VALUE : /[-+]?\.?\d+(?:[eE]\d+)?/
+VALUE : /[-+]?\d*\.?\d+(?:[eE]\d+)?/
{ $item[1] }
- | QUOTED_NAME
- {
- # 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
q[
CREATE TABLE orders (
order_id integer NOT NULL auto_increment,
- member_id varchar(255) comment 'fk to member',
+ member_id varchar(255) comment 'fk to ''member''',
billing_address_id int,
shipping_address_id int,
credit_card_id int,
is( $f2->data_type, 'varchar', 'Type is "varchar"' );
is( $f2->size, 255, 'Size is "255"' );
is( $f2->is_nullable, 1, 'Field can be null' );
- is( $f2->comments, 'fk to member', 'Field comment OK' );
+ is( $f2->comments, 'fk to \'member\'', 'Field comment OK' );
is( $f2->default_value, undef, 'Default value is undefined' );
my $f3 = shift @fields;
is( $f2->data_type, 'varchar', 'Type is "varchar"' );
is( $f2->size, 12, 'Size is "12"' );
is( $f2->is_nullable, 0, 'Field can not be null' );
- is( $f2->default_value, "test single quotes like in you''re", "Single quote in default value is escaped properly" );
+ is( $f2->default_value, "test single quotes like in you're", "Single quote in default value is unescaped properly" );
is( $f2->is_primary_key, 0, 'Field is not PK' );
# this is more of a sanity test because the original sqlt regex for default looked for an escaped quote represented as \'
is( $f3->data_type, 'varchar', 'Type is "varchar"' );
is( $f3->size, 20, 'Size is "20"' );
is( $f3->is_nullable, 0, 'Field can not be null' );
- is( $f3->default_value, "test single quotes escaped like you\\'re", "Single quote in default value is escaped properly" );
+ is( $f3->default_value, "test single quotes escaped like you're", "Single quote in default value is unescaped properly" );
is( $f3->is_primary_key, 0, 'Field is not PK' );
}