* MySQL parser correctly differentiates between signed and unsigned integer column
display sizes
* Replace Class::Accessor::Fast dependency with already-included Moo
+* Entire codebase is now free of tabs and trailing whitespace
# ----------------------------------------------------------
# 0.11010 2011-10-05
}
}
-tests_recursive ();
-
install_script (qw|
script/sqlt-diagram
script/sqlt-diff
install_share();
-auto_provides();
+tests_recursive ();
+
+
+# temporary(?) until I get around to fix M::I wrt xt/
+# needs Module::Install::AuthorTests
+eval {
+ # this should not be necessary since the autoloader is supposed
+ # to work, but there were reports of it failing
+ require Module::Install::AuthorTests;
+ recursive_author_tests (qw/xt/);
+ 1;
+} || do {
+ if ($Module::Install::AUTHOR) {
+ my $err = $@;
+
+ # better error message in case of missing dep
+ eval { require Module::Install::AuthorTests }
+ || die "\nYou need Module::Install::AuthorTests installed to run this Makefile.PL in author mode:\n\n$@\n";
+
+ die $err;
+ }
+};
auto_install();
=item * Parsers
-The parsers are responsible for reading the input files and describing
+The parsers are responsible for reading the input files and describing
them to the Schema object middleware.
=item * Producers
It's not necessary to understand how to write or manipulate any
of these for most common tasks, but you should aware of the concepts
-as they will be referenced later in this document.
+as they will be referenced later in this document.
=head1 SQLFAIRY SCRIPTS
=item * sqlt
This is the main interface for text-to-text translations, e.g.,
-converting a MySQL schema to Oracle.
+converting a MySQL schema to Oracle.
=item * sqlt-diagram
=item * sqlt-diff
This script will examine two schemas and report the SQL commands
-(ALTER, CREATE) needed to turn the first schema into the second.
+(ALTER, CREATE) needed to turn the first schema into the second.
=item * sqlt-dumper
(http://db.apache.org/torque/) project. The actual parsing of XML should be
trivial given the number of XML parsers available, so all that would be left
would be to map the specific concepts in the source file to the Schema objects
-in SQLFairy.
+in SQLFairy.
To convert a schema in SQLFairy's XML dialect to Oracle, do the following:
- $ sqlt -f XML-SQLFairy -t Oracle foo.xml > foo-oracle.sql
+ $ sqlt -f XML-SQLFairy -t Oracle foo.xml > foo-oracle.sql
=head1 SERIALIZING SCHEMAS
$ ...
SQLFairy has three serialization producers, none of which is superior
-to the other in their description of a schema.
+to the other in their description of a schema.
=over 4
=back
-=head1 AUTOMATED CODE-GENERATION
+=head1 AUTOMATED CODE-GENERATION
Given that so many applications interact with SQL databases, it's no
wonder that people have automated code to deal with this interaction.
$ sqlt-diff foo-v1.sql=MySQL foo-v2.sql=Oracle > diff.sql
As demonstrated, the schemas need not even be from the same vendor,
-though this is likely to produce some spurious results as
+though this is likely to produce some spurious results as
datatypes are not currently viewed equivalent unless they match
exactly, even if they would be converted to the same. For example,
MySQL's "integer" data type would be converted to Oracle's "number,"
but the differ isn't quite smart enough yet to figure this out. Also,
as the SQL to ALTER a field definition varies from database vendor to
vendor, these statements are made using just the keyword "CHANGE" and
-will likely need to be corrected for the target database.
+will likely need to be corrected for the target database.
=head1 A UNIFIED GRAPHICAL INTERFACE
learn the methods you can call. Here is a very simple example:
#!/usr/bin/perl
-
+
use strict;
use SQL::Translator;
-
+
my $input = q[
create table foo (
foo_id int not null default '0' primary key,
foo_name varchar(30) not null default ''
);
-
+
create table bar (
bar_id int not null default '0' primary key,
bar_value varchar(100) not null default ''
);
];
-
+
my $t = SQL::Translator->new;
$t->parser('MySQL') or die $t->error;
$t->producer( \&produce ) or die $t->error;
my $output = $t->translate( \$input ) or die $t->error;
print $output;
-
+
sub produce {
my $tr = shift;
my $schema = $tr->schema;
Executing this script produces the following:
- $ ./my-producer.pl
+ $ ./my-producer.pl
Table = foo
Table = bar
map the concepts in the data to the Schema object.
#!/usr/bin/perl
-
+
use strict;
use SQL::Translator;
-
+
my $input =
"foo:foo_id int 11:foo_name varchar 30\n" .
"bar:bar_id int 11:bar_value varchar 30"
;
-
+
my $t = SQL::Translator->new;
$t->parser( \&parser ) or die $t->error;
$t->producer('Oracle') or die $t->error;
my $output = $t->translate( \$input ) or die $t->error;
print $output;
-
+
sub parser {
my ( $tr, $data ) = @_;
my $schema = $tr->schema;
-
+
for my $line ( split( /\n/, $data ) ) {
my ( $table_name, @fields ) = split( /:/, $line );
my $table = $schema->add_table( name => $table_name )
eofile : /^\Z/
-statement :
+statement :
comment
| create
| <error>
OUTER: /outer/i
WHERE: /where/i
-
+
trigger_name: SCHEMA '.' NAME
{ $return = { schema => $item[1], name => $item[3] } }
| NAME
- { $return = { name => $item[1] } }
+ { $return = { name => $item[1] } }
table_name: SCHEMA '.' NAME
{ $return = { schema => $item[1], name => $item[3] } }
| NAME
- { $return = { name => $item[1] } }
+ { $return = { name => $item[1] } }
view_name: SCHEMA '.' NAME
{ $return = { schema => $item[1], name => $item[3] } }
| NAME
- { $return = { name => $item[1] } }
+ { $return = { name => $item[1] } }
column_name: NAME
NAME: /\w+/
NAME: /\w{1,18}/
-
+
options: /WITH/i ( /CASCADED/i | /LOCAL/i ) /CHECK\s+OPTION/i
# root_view_definition: /MODE\s+DB2SQL/i '(' oid_column ( /,/ with_options )(?) ')'
common_table_expression: table_name column_list /AS/i get_bracketed
{
- $return = { name => $item{table_name}{name},
+ $return = { name => $item{table_name}{name},
query => $item[4]
};
}
-get_bracketed:
-{
+get_bracketed:
+{
extract_bracketed($text, '(');
}
# fullselect: ( subselect | '(' fullselect ')' | values_clause ) ( ( /UNION/i | /UNION/i /ALL/i | /EXCEPT/i | /EXCEPT/i /ALL/i | /INTERSECT/i | /INTERSECT/i /ALL/i ) ( subselect | '(' fullselect ')' | values_clause ) )(s)
-# values_clause: /VALUES/i values_row(s /,/)
+# values_clause: /VALUES/i values_row(s /,/)
# values_row: ( expression | /NULL/i ) | '(' ( expression | /NULL/i )(s /,/) ')'
# from_clause: /FROM/i table_reference(s /,/)
-# table_reference:
-# (
-# ( nickname
-# | table_name
-# | view_name
-# )
+# table_reference:
+# (
+# ( nickname
+# | table_name
+# | view_name
+# )
# | ( /ONLY/i
-# | /OUTER/i
-# ) '('
-# ( table_name
-# | view_name
-# ) ')'
-# ) correlation_clause(?)
-# | TABLE '(' function_name '(' expression(s? /,/) ')' ')' correlation_clause
-# | TABLE(?) '(' fullselect ')' correlation_clause
-# | joined_table
-
+# | /OUTER/i
+# ) '('
+# ( table_name
+# | view_name
+# ) ')'
+# ) correlation_clause(?)
+# | TABLE '(' function_name '(' expression(s? /,/) ')' ')' correlation_clause
+# | TABLE(?) '(' fullselect ')' correlation_clause
+# | joined_table
+
# correlation_clause: /AS/i(?) correlation_name column_list(?)
-# joined_table:
-# table_reference ( INNER
-# | outer
+# joined_table:
+# table_reference ( INNER
+# | outer
# )(?) JOIN table_reference ON join_condition
# | '(' joined_table ')'
-
+
# outer: ( LEFT | RIGHT | FULL ) OUTER(?)
where_clause: WHERE search_condition
-# group_by_clause: /GROUP\s+BY/i ( grouping_expression
+# group_by_clause: /GROUP\s+BY/i ( grouping_expression
# | grouping_sets
# | super_groups
# )(s /,/)
# # Name of one of the selected columns!
# simple_column_name: NAME
-# simple_integer: /\d+/
+# simple_integer: /\d+/
# { $item[1] <= $numberofcolumns && $item[1] > 1 }
# sort_key_expression: expression
# { expression from select columns list, grouping_expression, column function.. }
-# grouping_sets: /GROUPING\s+SETS/i '(' (
-# ( grouping_expression
-# | super_groups
-# )
-# | '(' ( grouping_expression
-# | super_groups
-# )(s /,/) ')'
-# )(s /,/) ')'
+# grouping_sets: /GROUPING\s+SETS/i '(' (
+# ( grouping_expression
+# | super_groups
+# )
+# | '(' ( grouping_expression
+# | super_groups
+# )(s /,/) ')'
+# )(s /,/) ')'
-# super_groups: /ROLLUP/i '(' grouping_expression_list ')'
+# super_groups: /ROLLUP/i '(' grouping_expression_list ')'
# | /CUBE/i '(' grouping_expression_list ')'
# | grand_total
-# grouping_expression_list: ( grouping_expression
-# | '(' grouping_expression(s /,/) ')'
+# grouping_expression_list: ( grouping_expression
+# | '(' grouping_expression(s /,/) ')'
# )(s /,/)
# grand_total: '(' ')'
after: /AFTER/i
-type: /UPDATE/i /OF/i column_name(s /,/)
+type: /UPDATE/i /OF/i column_name(s /,/)
{ $return = { event => 'update_on',
fields => $item[3] }
}
reference_b: /REFERENCING/i old_new_corr(0..2)
{ $return = join(' ', $item[1], join(' ', @{$item[2]}) ) }
-reference_a: /REFERENCING/i old_new_corr(0..2) old_new_table(0..2)
+reference_a: /REFERENCING/i old_new_corr(0..2) old_new_table(0..2)
{ $return = join(' ', $item[1], join(' ', @{$item[2]}), join(' ', @{$item[3]}) ) }
-old_new_corr: /OLD/i /(AS)?/i correlation_name
+old_new_corr: /OLD/i /(AS)?/i correlation_name
{ $return = join(' ', @item[1..3] ) }
| /NEW/i /(AS)?/i correlation_name
{ $return = join(' ', @item[1..3] ) }
# Just parsing simple search conditions for now.
search_condition: /[^)]+/
-expression: (
- ( '+'
- | '-'
- )(?)
+expression: (
+ ( '+'
+ | '-'
+ )(?)
( function
| '(' expression ')'
| constant
| column_name
| host_variable
| special_register
- | '(' scalar_fullselect ')'
+ | '(' scalar_fullselect ')'
| labeled_duration
| case_expression
| cast_specification
| OLAP_function
| method_invocation
| subtype_treatment
- | sequence_reference
+ | sequence_reference
)
)(s /operator/)
-operator: ( /CONCAT/i | '||' ) | '/' | '*' | '+' | '-'
+operator: ( /CONCAT/i | '||' ) | '/' | '*' | '+' | '-'
-function: ( /SYSIBM\.|/i sysibm_function
+function: ( /SYSIBM\.|/i sysibm_function
| /SYSFUN\.|/i sysfun_function
- | userdefined_function
+ | userdefined_function
) '(' func_args(s /,/) ')'
constant: int_const | float_const | dec_const | char_const | hex_const | grastr_const
labeled_duration: ld_type ld_duration
-ld_type: function
- | '(' expression ')'
- | constant
- | column_name
+ld_type: function
+ | '(' expression ')'
+ | constant
+ | column_name
| host_variable
-ld_duration: /YEARS?/i
- | /MONTHS?/i
- | /DAYS?/i
- | /HOURS?/i
+ld_duration: /YEARS?/i
+ | /MONTHS?/i
+ | /DAYS?/i
+ | /HOURS?/i
| /MINUTES?/i
| /SECONDS?/i
| /MICROSECONDS?/i
-case_expression: /CASE/i ( searched_when_clause
- | simple_when_clause
- )
- ( /ELSE\s+NULL/i
- | /ELSE/i result_expression
+case_expression: /CASE/i ( searched_when_clause
+ | simple_when_clause
+ )
+ ( /ELSE\s+NULL/i
+ | /ELSE/i result_expression
)(?) /END/i
-searched_when_clause: ( /WHEN/i search_condition /THEN/i
- ( result_expression
+searched_when_clause: ( /WHEN/i search_condition /THEN/i
+ ( result_expression
| /NULL/i
)
)(s)
-simple_when_clause: expression ( /WHEN/i search_condition /THEN/i
- ( result_expression
+simple_when_clause: expression ( /WHEN/i search_condition /THEN/i
+ ( result_expression
| /NULL/i
)
)(s)
-result_expression: expression
+result_expression: expression
-cast_specification: /CAST/i '(' ( expression
+cast_specification: /CAST/i '(' ( expression
| /NULL/i
| parameter_marker
- ) /AS/i data_type
- ( /SCOPE/ ( typed_table_name
+ ) /AS/i data_type
+ ( /SCOPE/ ( typed_table_name
| typed_view_name
)
)(?) ')'
-dereference_operation: scoped_reference_expression '->' name1
+dereference_operation: scoped_reference_expression '->' name1
( '(' expression(s) ')' )(?)
# ( '(' expression(s /,/) ')' )(?)
-scoped_reference_expression: expression
-{ # scoped, reference
+scoped_reference_expression: expression
+{ # scoped, reference
}
name1: NAME
-OLAP_function: ranking_function
+OLAP_function: ranking_function
| numbering_function
| aggregation_function
-ranking_function: ( /RANK/ '()'
- | /DENSE_RANK|DENSERANK/i '()'
+ranking_function: ( /RANK/ '()'
+ | /DENSE_RANK|DENSERANK/i '()'
) /OVER/i '(' window_partition_clause(?) window_order_clause ')'
-numbering_function: /ROW_NUMBER|ROWNUMBER/i '()' /OVER/i '(' window_partition_clause(?)
- ( window_order_clause window_aggregation_group_clause(?)
- )(?)
- ( /RANGE\s+BETWEEN\s+UNBOUNDED\s+PRECEDING\s+AND\s+UNBBOUNDED\s+FOLLOWING/i
+numbering_function: /ROW_NUMBER|ROWNUMBER/i '()' /OVER/i '(' window_partition_clause(?)
+ ( window_order_clause window_aggregation_group_clause(?)
+ )(?)
+ ( /RANGE\s+BETWEEN\s+UNBOUNDED\s+PRECEDING\s+AND\s+UNBBOUNDED\s+FOLLOWING/i
| window_aggregation_group_clause
)(?) ')'
window_partition_clause: /PARTITION\s+BY/i partitioning_expression(s /,/)
-window_order_clause: /ORDER\s+BY/i
- ( sort_key_expression
- ( asc_option
- | desc_option
+window_order_clause: /ORDER\s+BY/i
+ ( sort_key_expression
+ ( asc_option
+ | desc_option
)(?)
)(s /,/)
window_aggregation_group_clause: ( /ROWS/i
| /RANGE/i
- )
+ )
( group_start
| group_between
| group_end
)
-group_start: /UNBOUNDED\s+PRECEDING/i
+group_start: /UNBOUNDED\s+PRECEDING/i
| unsigned_constant /PRECEDING/i
| /CURRENT\s+ROW/i
group_between: /BETWEEN/i group_bound1 /AND/i group_bound2
-group_bound1: /UNBOUNDED\s+PRECEDING/i
+group_bound1: /UNBOUNDED\s+PRECEDING/i
| unsigned_constant /PRECEDING/i
| unsigned_constant /FOLLOWING/i
| /CURRENT\s+ROW/i
-group_bound2: /UNBOUNDED\s+PRECEDING/i
+group_bound2: /UNBOUNDED\s+PRECEDING/i
| unsigned_constant /PRECEDING/i
| unsigned_constant /FOLLOWING/i
| /CURRENT\s+ROW/i
-group_end: /UNBOUNDED\s+PRECEDING/i
- | unsigned_constant /FOLLOWING/i
+group_end: /UNBOUNDED\s+PRECEDING/i
+ | unsigned_constant /FOLLOWING/i
method_invocation: subject_expression '..' method_name
- ( '(' expression(s) ')'
-# ( '(' expression(s /,/) ')'
+ ( '(' expression(s) ')'
+# ( '(' expression(s /,/) ')'
)(?)
subject_expression: expression
-{ # with static result type that is a used-defined struct type
+{ # with static result type that is a used-defined struct type
}
method_name: NAME
-{ # must be a method of subject_expression
+{ # must be a method of subject_expression
}
subtype_treatment: /TREAT/i '(' expression /AS/i data_type ')'
cond: ( /AND/i | /OR/i ) /NOT|/i ( predicate ( /SELECTIVITY/i numeric_constant )(?) | '(' search_condition ')' )
-predicate: basic_p | quantified_p | between_p | exists_p | in_p | like_p | null_p | type_p
+predicate: basic_p | quantified_p | between_p | exists_p | in_p | like_p | null_p | type_p
basic_p: expression /(=|<>|<|>|<=|=>|\^=|\^<|\^>|\!=)/ expression
disable_constraints : if_exists(?) /alter/i /table/i ident /nocheck/i /constraint/i /all/i END_STATEMENT
-# this is for the normal case
+# this is for the normal case
create_constraint : /create/i constraint END_STATEMENT
{
@table_comments = ();
"CREATE OR REPLACE TRIGGER $trig_name\n".
"BEFORE INSERT OR UPDATE ON $table_name_q\n".
"FOR EACH ROW WHEN (new.$field_name_q IS NULL)\n".
- "BEGIN \n".
+ "BEGIN\n".
" SELECT sysdate INTO :new.$field_name_q FROM dual;\n".
"END;\n";
General Parser Options:
--skip Comma-separated list of tables to skip (only implemented in some parsers)
- --ignore_opts Comma-separated list of table options to ignore
+ --ignore_opts Comma-separated list of table options to ignore
DBI Parser Options:
) or pod2usage(2);
if ($use_same_auth) {
- $producer_dsn = $dsn;
- $producer_db_user = $db_user;
- $producer_db_password = $db_password;
+ $producer_dsn = $dsn;
+ $producer_db_user = $db_user;
+ $producer_db_password = $db_password;
}
-if (
+if (
( !defined $from && defined $dsn )
||
$from =~ /^DBI.*/
exit(0);
}
-my $translator = SQL::Translator->new(
+my $translator = SQL::Translator->new(
debug => $debug || 0,
trace => $trace || 0,
no_comments => $no_comments || 0,
newlines => $newlines,
postgres_version => $postgres_version,
mysql_version => $mysql_version,
- package_name => $package_name,
+ package_name => $package_name,
},
);
$translator->producer($to);
for my $file (@files) {
- my @args =
+ my @args =
($file eq '-') ? (data => \*STDIN) :
($file eq '!') ? (data => '') :
(file => $file);
# 02111-1307 USA
# -------------------------------------------------------------------
-=head1 NAME
+=head1 NAME
sqlt-diagram - Automatically create a diagram from a database schema
default "medium")
--gutter Gutter size between tables
--color Add colors
- --show-fk-only Only show fields that act as primary
+ --show-fk-only Only show fields that act as primary
or foreign keys
--natural-join Perform natural joins
--natural-join-pk Perform natural joins from primary keys only
-s|--skip Fields to skip in natural joins
- --skip-tables Comma-separated list of table names to exclude
+ --skip-tables Comma-separated list of table names to exclude
--skip-tables-like Comma-separated list of regexen to exclude tables
--debug Print debugging information
#
# Get arguments.
#
-my (
- $out_file, $image_type, $db_driver, $title, $num_columns,
+my (
+ $out_file, $image_type, $db_driver, $title, $num_columns,
$no_lines, $font_size, $add_color, $debug, $show_fk_only,
- $gutter, $natural_join, $join_pk_only, $skip_fields,
+ $gutter, $natural_join, $join_pk_only, $skip_fields,
$skip_tables, $skip_tables_like, $help
);
pod2usage( -message => "No db driver specified" ) unless $db_driver;
pod2usage( -message => 'No input file' ) unless @files;
-my $translator = SQL::Translator->new(
+my $translator = SQL::Translator->new(
from => $db_driver,
to => 'Diagram',
debug => $debug || 0,
=head1 DESCRIPTION
sqlt-diff is a utility for creating a file of SQL commands necessary to
-transform the first schema provided to the second. While not yet
-exhaustive in its ability to mutate the entire schema, it will report the
+transform the first schema provided to the second. While not yet
+exhaustive in its ability to mutate the entire schema, it will report the
following
=over
=item * Missing/altered fields
-Any fields missing or altered between the two schemas will be reported
+Any fields missing or altered between the two schemas will be reported
as:
- ALTER TABLE <table_name>
- [DROP <field_name>]
+ ALTER TABLE <table_name>
+ [DROP <field_name>]
[CHANGE <field_name> <datatype> (<size>)] ;
=item * Missing/altered indices
Any indices missing or of a different type or on different fields will be
indicated. Indices that should be dropped will be reported as such:
-
+
DROP INDEX <index_name> ON <table_name> ;
-An index of a different type or on different fields will be reported as a
+An index of a different type or on different fields will be reported as a
new index as such:
- CREATE [<index_type>] INDEX [<index_name>] ON <table_name>
+ CREATE [<index_type>] INDEX [<index_name>] ON <table_name>
( <field_name>[,<field_name>] ) ;
=back
use vars qw( $VERSION );
$VERSION = '1.59';
-my ( @input, $list, $help, $debug, $trace, $caseopt, $ignore_index_names,
- $ignore_constraint_names, $output_db, $mysql_parser_version,
- $ignore_view_sql, $ignore_proc_sql, $no_batch_alters );
+my ( @input, $list, $help, $debug, $trace, $caseopt, $ignore_index_names,
+ $ignore_constraint_names, $output_db, $mysql_parser_version,
+ $ignore_view_sql, $ignore_proc_sql, $no_batch_alters );
for my $arg ( @ARGV ) {
if ( $arg =~ m/^-?-l(ist)?$/ ) {
$list = 1;
$help = 1;
}
elsif ( $arg =~ m/^-?-d(ebug)?$/ ) {
- $debug = 1;
+ $debug = 1;
}
elsif ( $arg =~ m/^-?-t(race)?$/ ) {
- $trace = 1;
+ $trace = 1;
}
elsif ( $arg =~ m/^-?-c(ase-insensitive)?$/ ) {
- $caseopt = 1;
+ $caseopt = 1;
}
elsif ( $arg =~ m/^--ignore-index-names$/ ) {
- $ignore_index_names = 1;
+ $ignore_index_names = 1;
}
elsif ( $arg =~ m/^--ignore-constraint-names$/ ) {
- $ignore_constraint_names = 1;
+ $ignore_constraint_names = 1;
}
elsif ( $arg =~ m/^--mysql-parser-version=(.+)$/ ) {
- $mysql_parser_version = $1;
+ $mysql_parser_version = $1;
}
elsif ( $arg =~ m/^--output-db=(.+)$/ ) {
- $output_db = $1;
+ $output_db = $1;
}
elsif ( $arg =~ m/^--ignore-view-sql$/ ) {
- $ignore_view_sql = 1;
+ $ignore_view_sql = 1;
}
elsif ( $arg =~ m/^--ignore-proc-sql$/ ) {
- $ignore_proc_sql = 1;
+ $ignore_proc_sql = 1;
}
elsif ( $arg =~ m/^([^=]+)=(.+)$/ ) {
push @input, { file => $1, parser => $2 };
}
print STDERR <<'EOM';
-This code is experimental, currently the new code only supports MySQL or
+This code is experimental, currently the new code only supports MySQL or
SQLite diffing. To add support for other databases, please patch the relevant
SQL::Translator::Producer:: module. If you need compatibility with the old
sqlt-diff, please use sqlt-diff-old, and look into helping us make this one
($schema, $parser);
} @input;
-my $result = SQL::Translator::Diff::schema_diff($source_schema, $source_db,
+my $result = SQL::Translator::Diff::schema_diff($source_schema, $source_db,
$target_schema, $target_db,
{ caseopt => $caseopt,
ignore_index_names => $ignore_index_names,
=head1 DESCRIPTION
sqlt-diff is a utility for creating a file of SQL commands necessary to
-transform the first schema provided to the second. While not yet
-exhaustive in its ability to mutate the entire schema, it will report the
+transform the first schema provided to the second. While not yet
+exhaustive in its ability to mutate the entire schema, it will report the
following
=over
=item * Missing/altered fields
-Any fields missing or altered between the two schemas will be reported
+Any fields missing or altered between the two schemas will be reported
as:
- ALTER TABLE <table_name>
- [DROP <field_name>]
+ ALTER TABLE <table_name>
+ [DROP <field_name>]
[CHANGE <field_name> <datatype> (<size>)] ;
=item * Missing/altered indices
Any indices missing or of a different type or on different fields will be
indicated. Indices that should be dropped will be reported as such:
-
+
DROP INDEX <index_name> ON <table_name> ;
-An index of a different type or on different fields will be reported as a
+An index of a different type or on different fields will be reported as a
new index as such:
- CREATE [<index_type>] INDEX [<index_name>] ON <table_name>
+ CREATE [<index_type>] INDEX [<index_name>] ON <table_name>
( <field_name>[,<field_name>] ) ;
=back
$help = 1;
}
elsif ( $arg =~ m/^-?-d(ebug)?$/ ) {
- $debug = 1;
+ $debug = 1;
}
elsif ( $arg =~ m/^([^=]+)=(.+)$/ ) {
push @input, { file => $1, parser => $2 };
warn "TABLE '$s1_name.$t1_name'\n" if $debug;
unless ( $t2 ) {
- warn "Couldn't find table '$s1_name.$t1_name' in '$s2_name'\n"
+ warn "Couldn't find table '$s1_name.$t1_name' in '$s2_name'\n"
if $debug;
if ( $target_db =~ /(SQLServer|Oracle)/ ) {
- for my $constraint ( $t1->get_constraints ) {
- next if $constraint->type ne FOREIGN_KEY;
- push @diffs_at_end, "ALTER TABLE $t1_name ADD ".
- constraint_to_string($constraint, $source_schema).";";
- $t1->drop_constraint($constraint);
- }
+ for my $constraint ( $t1->get_constraints ) {
+ next if $constraint->type ne FOREIGN_KEY;
+ push @diffs_at_end, "ALTER TABLE $t1_name ADD ".
+ constraint_to_string($constraint, $source_schema).";";
+ $t1->drop_constraint($constraint);
+ }
}
push @new_tables, $t1;
next;
}
-
+
# Go through our options
- my $options_different = 0;
- my %checkedOptions;
+ my $options_different = 0;
+ my %checkedOptions;
OPTION:
- for my $t1_option_ref ( $t1->options ) {
- my($key1, $value1) = %{$t1_option_ref};
- for my $t2_option_ref ( $t2->options ) {
- my($key2, $value2) = %{$t2_option_ref};
- if ( $key1 eq $key2 ) {
- if ( defined $value1 != defined $value2 ) {
- $options_different = 1;
- last OPTION;
- }
- if ( defined $value1 && $value1 ne $value2 ) {
- $options_different = 1;
- last OPTION;
- }
- $checkedOptions{$key1} = 1;
- next OPTION;
- }
- }
- $options_different = 1;
- last OPTION;
- }
+ for my $t1_option_ref ( $t1->options ) {
+ my($key1, $value1) = %{$t1_option_ref};
+ for my $t2_option_ref ( $t2->options ) {
+ my($key2, $value2) = %{$t2_option_ref};
+ if ( $key1 eq $key2 ) {
+ if ( defined $value1 != defined $value2 ) {
+ $options_different = 1;
+ last OPTION;
+ }
+ if ( defined $value1 && $value1 ne $value2 ) {
+ $options_different = 1;
+ last OPTION;
+ }
+ $checkedOptions{$key1} = 1;
+ next OPTION;
+ }
+ }
+ $options_different = 1;
+ last OPTION;
+ }
# Go through the other table's options
unless ( $options_different ) {
- for my $t2_option_ref ( $t2->options ) {
- my($key, $value) = %{$t2_option_ref};
- next if $checkedOptions{$key};
- $options_different = 1;
- last;
- }
+ for my $t2_option_ref ( $t2->options ) {
+ my($key, $value) = %{$t2_option_ref};
+ next if $checkedOptions{$key};
+ $options_different = 1;
+ last;
+ }
}
# If there's a difference, just re-set all the options
my @diffs_table_options;
if ( $options_different ) {
- my @options = ();
- foreach my $option_ref ( $t1->options ) {
- my($key, $value) = %{$option_ref};
- push(@options, defined $value ? "$key=$value" : $key);
- }
- my $options = join(' ', @options);
- @diffs_table_options = ("ALTER TABLE $t1_name $options;");
+ my @options = ();
+ foreach my $option_ref ( $t1->options ) {
+ my($key, $value) = %{$option_ref};
+ push(@options, defined $value ? "$key=$value" : $key);
+ }
+ my $options = join(' ', @options);
+ @diffs_table_options = ("ALTER TABLE $t1_name $options;");
}
-
+
my $t2_name = $t2->name;
my(@diffs_table_adds, @diffs_table_changes);
for my $t1_field ( $t1->get_fields ) {
my $f2_full_name = "$s2_name.$t2_name.$f1_name";
unless ( $t2_field ) {
- warn "Couldn't find field '$f2_full_name' in '$t2_name'\n"
+ warn "Couldn't find field '$f2_full_name' in '$t2_name'\n"
if $debug;
my $temp_default_value = 0;
if ( $target_db =~ /SQLServer/ && !$f1_nullable && !defined $f1_default ) {
- # SQL Server doesn't allow adding non-nullable, non-default columns
- # so we add it with a default value, then remove the default value
- $temp_default_value = 1;
- my(@numeric_types) = qw(decimal numeric float real int bigint smallint tinyint);
- $f1_default = grep($_ eq $f1_type, @numeric_types) ? 0 : '';
+ # SQL Server doesn't allow adding non-nullable, non-default columns
+ # so we add it with a default value, then remove the default value
+ $temp_default_value = 1;
+ my(@numeric_types) = qw(decimal numeric float real int bigint smallint tinyint);
+ $f1_default = grep($_ eq $f1_type, @numeric_types) ? 0 : '';
}
push @diffs_table_adds, sprintf( "ALTER TABLE %s ADD %s%s %s%s%s%s%s%s;",
$t1_name, $target_db =~ /Oracle/ ? '(' : '',
$f1_name, $f1_type,
($f1_size && $f1_type !~ /(blob|text)$/) ? "($f1_size)" : '',
!defined $f1_default ? ''
- : uc $f1_default eq 'NULL' ? ' DEFAULT NULL'
- : uc $f1_default eq 'CURRENT_TIMESTAMP' ? ' DEFAULT CURRENT_TIMESTAMP'
- : " DEFAULT '$f1_default'",
+ : uc $f1_default eq 'NULL' ? ' DEFAULT NULL'
+ : uc $f1_default eq 'CURRENT_TIMESTAMP' ? ' DEFAULT CURRENT_TIMESTAMP'
+ : " DEFAULT '$f1_default'",
$f1_nullable ? '' : ' NOT NULL',
$f1_auto_inc ? ' AUTO_INCREMENT' : '',
$target_db =~ /Oracle/ ? ')' : '',
);
if ( $temp_default_value ) {
- undef $f1_default;
- push @diffs_table_adds, sprintf( <<END
+ undef $f1_default;
+ push @diffs_table_adds, sprintf( <<END
DECLARE \@defname VARCHAR(100), \@cmd VARCHAR(1000)
-SET \@defname =
-(SELECT name
+SET \@defname =
+(SELECT name
FROM sysobjects so JOIN sysconstraints sc
-ON so.id = sc.constid
-WHERE object_name(so.parent_obj) = '%s'
+ON so.id = sc.constid
+WHERE object_name(so.parent_obj) = '%s'
AND so.xtype = 'D'
-AND sc.colid =
- (SELECT colid FROM syscolumns
- WHERE id = object_id('%s') AND
+AND sc.colid =
+ (SELECT colid FROM syscolumns
+ WHERE id = object_id('%s') AND
name = '%s'))
SET \@cmd = 'ALTER TABLE %s DROP CONSTRAINT '
+ \@defname
EXEC(\@cmd)
END
- , $t1_name, $t1_name, $f1_name, $t1_name,
- );
+ , $t1_name, $t1_name, $f1_name, $t1_name,
+ );
}
next;
}
my $f2_default = $t2_field->default_value;
my $f2_auto_inc = $t2_field->is_auto_increment;
if ( !$t1_field->equals($t2_field, $case_insensitive) ) {
- # SQLServer timestamp fields can't be altered, so we drop and add instead
- if ( $target_db =~ /SQLServer/ && $f2_type eq "timestamp" ) {
- push @diffs_table_changes, "ALTER TABLE $t1_name DROP COLUMN $f1_name;";
- push @diffs_table_changes, sprintf( "ALTER TABLE %s ADD %s%s %s%s%s%s%s%s;",
- $t1_name, $target_db =~ /Oracle/ ? '(' : '',
- $f1_name, $f1_type,
- ($f1_size && $f1_type !~ /(blob|text)$/) ? "($f1_size)" : '',
- !defined $f1_default ? ''
- : uc $f1_default eq 'NULL' ? ' DEFAULT NULL'
- : uc $f1_default eq 'CURRENT_TIMESTAMP' ? ' DEFAULT CURRENT_TIMESTAMP'
- : " DEFAULT '$f1_default'",
- $f1_nullable ? '' : ' NOT NULL',
- $f1_auto_inc ? ' AUTO_INCREMENT' : '',
- $target_db =~ /Oracle/ ? ')' : '',
- );
- next;
- }
-
- my $changeText = $target_db =~ /SQLServer/ ? 'ALTER COLUMN' :
- $target_db =~ /Oracle/ ? 'MODIFY (' : 'CHANGE';
- my $nullText = $f1_nullable ? '' : ' NOT NULL';
- $nullText = '' if $target_db =~ /Oracle/ && $f1_nullable == $f2_nullable;
+ # SQLServer timestamp fields can't be altered, so we drop and add instead
+ if ( $target_db =~ /SQLServer/ && $f2_type eq "timestamp" ) {
+ push @diffs_table_changes, "ALTER TABLE $t1_name DROP COLUMN $f1_name;";
+ push @diffs_table_changes, sprintf( "ALTER TABLE %s ADD %s%s %s%s%s%s%s%s;",
+ $t1_name, $target_db =~ /Oracle/ ? '(' : '',
+ $f1_name, $f1_type,
+ ($f1_size && $f1_type !~ /(blob|text)$/) ? "($f1_size)" : '',
+ !defined $f1_default ? ''
+ : uc $f1_default eq 'NULL' ? ' DEFAULT NULL'
+ : uc $f1_default eq 'CURRENT_TIMESTAMP' ? ' DEFAULT CURRENT_TIMESTAMP'
+ : " DEFAULT '$f1_default'",
+ $f1_nullable ? '' : ' NOT NULL',
+ $f1_auto_inc ? ' AUTO_INCREMENT' : '',
+ $target_db =~ /Oracle/ ? ')' : '',
+ );
+ next;
+ }
+
+ my $changeText = $target_db =~ /SQLServer/ ? 'ALTER COLUMN' :
+ $target_db =~ /Oracle/ ? 'MODIFY (' : 'CHANGE';
+ my $nullText = $f1_nullable ? '' : ' NOT NULL';
+ $nullText = '' if $target_db =~ /Oracle/ && $f1_nullable == $f2_nullable;
push @diffs_table_changes, sprintf( "ALTER TABLE %s %s %s%s %s%s%s%s%s%s;",
$t1_name, $changeText,
$f1_name, $target_db =~ /MySQL/ ? " $f1_name" : '',
$f1_type, ($f1_size && $f1_type !~ /(blob|text)$/) ? "($f1_size)" : '',
$nullText,
!defined $f1_default || $target_db =~ /SQLServer/ ? ''
- : uc $f1_default eq 'NULL' ? ' DEFAULT NULL'
- : uc $f1_default eq 'CURRENT_TIMESTAMP' ? ' DEFAULT CURRENT_TIMESTAMP'
- : " DEFAULT '$f1_default'",
+ : uc $f1_default eq 'NULL' ? ' DEFAULT NULL'
+ : uc $f1_default eq 'CURRENT_TIMESTAMP' ? ' DEFAULT CURRENT_TIMESTAMP'
+ : " DEFAULT '$f1_default'",
$f1_auto_inc ? ' AUTO_INCREMENT' : '',
$target_db =~ /Oracle/ ? ')' : '',
);
if ( defined $f1_default && $target_db =~ /SQLServer/ ) {
- # Adding a column with a default value for SQL Server means adding a
- # constraint and setting existing NULLs to the default value
- push @diffs_table_changes, sprintf( "ALTER TABLE %s ADD CONSTRAINT DF_%s_%s %s FOR %s;",
- $t1_name, $t1_name, $f1_name, uc $f1_default eq 'NULL' ? 'DEFAULT NULL'
- : uc $f1_default eq 'CURRENT_TIMESTAMP' ? 'DEFAULT CURRENT_TIMESTAMP'
- : "DEFAULT '$f1_default'", $f1_name,
+ # Adding a column with a default value for SQL Server means adding a
+ # constraint and setting existing NULLs to the default value
+ push @diffs_table_changes, sprintf( "ALTER TABLE %s ADD CONSTRAINT DF_%s_%s %s FOR %s;",
+ $t1_name, $t1_name, $f1_name, uc $f1_default eq 'NULL' ? 'DEFAULT NULL'
+ : uc $f1_default eq 'CURRENT_TIMESTAMP' ? 'DEFAULT CURRENT_TIMESTAMP'
+ : "DEFAULT '$f1_default'", $f1_name,
);
- push @diffs_table_changes, sprintf( "UPDATE %s SET %s = %s WHERE %s IS NULL;",
- $t1_name, $f1_name, uc $f1_default eq 'NULL' ? 'NULL'
- : uc $f1_default eq 'CURRENT_TIMESTAMP' ? 'CURRENT_TIMESTAMP'
- : "'$f1_default'", $f1_name,
+ push @diffs_table_changes, sprintf( "UPDATE %s SET %s = %s WHERE %s IS NULL;",
+ $t1_name, $f1_name, uc $f1_default eq 'NULL' ? 'NULL'
+ : uc $f1_default eq 'CURRENT_TIMESTAMP' ? 'CURRENT_TIMESTAMP'
+ : "'$f1_default'", $f1_name,
);
}
}
}
-
- my(%checked_indices, @diffs_index_creates, @diffs_index_drops);
+
+ my(%checked_indices, @diffs_index_creates, @diffs_index_drops);
INDEX:
- for my $i1 ( $t1->get_indices ) {
- for my $i2 ( $t2->get_indices ) {
- if ( $i1->equals($i2, $case_insensitive) ) {
- $checked_indices{$i2} = 1;
- next INDEX;
- }
- }
- push @diffs_index_creates, sprintf(
+ for my $i1 ( $t1->get_indices ) {
+ for my $i2 ( $t2->get_indices ) {
+ if ( $i1->equals($i2, $case_insensitive) ) {
+ $checked_indices{$i2} = 1;
+ next INDEX;
+ }
+ }
+ push @diffs_index_creates, sprintf(
"CREATE %sINDEX%s ON %s (%s);",
$i1->type eq NORMAL ? '' : $i1->type." ",
$i1->name ? " ".$i1->name : '',
$t1_name,
join(",", $i1->fields),
);
- }
+ }
INDEX2:
- for my $i2 ( $t2->get_indices ) {
- next if $checked_indices{$i2};
- for my $i1 ( $t1->get_indices ) {
- next INDEX2 if $i2->equals($i1, $case_insensitive);
- }
- $target_db =~ /SQLServer/
- ? push @diffs_index_drops, "DROP INDEX $t1_name.".$i2->name.";"
- : push @diffs_index_drops, "DROP INDEX ".$i2->name." on $t1_name;";
- }
-
- my(%checked_constraints, @diffs_constraint_drops);
+ for my $i2 ( $t2->get_indices ) {
+ next if $checked_indices{$i2};
+ for my $i1 ( $t1->get_indices ) {
+ next INDEX2 if $i2->equals($i1, $case_insensitive);
+ }
+ $target_db =~ /SQLServer/
+ ? push @diffs_index_drops, "DROP INDEX $t1_name.".$i2->name.";"
+ : push @diffs_index_drops, "DROP INDEX ".$i2->name." on $t1_name;";
+ }
+
+ my(%checked_constraints, @diffs_constraint_drops);
CONSTRAINT:
- for my $c1 ( $t1->get_constraints ) {
- next if $source_db =~ /Oracle/ && $c1->type eq UNIQUE && $c1->name =~ /^SYS_/i;
- for my $c2 ( $t2->get_constraints ) {
- if ( $c1->equals($c2, $case_insensitive) ) {
- $checked_constraints{$c2} = 1;
- next CONSTRAINT;
- }
- }
- push @diffs_at_end, "ALTER TABLE $t1_name ADD ".
- constraint_to_string($c1, $source_schema).";";
- }
+ for my $c1 ( $t1->get_constraints ) {
+ next if $source_db =~ /Oracle/ && $c1->type eq UNIQUE && $c1->name =~ /^SYS_/i;
+ for my $c2 ( $t2->get_constraints ) {
+ if ( $c1->equals($c2, $case_insensitive) ) {
+ $checked_constraints{$c2} = 1;
+ next CONSTRAINT;
+ }
+ }
+ push @diffs_at_end, "ALTER TABLE $t1_name ADD ".
+ constraint_to_string($c1, $source_schema).";";
+ }
CONSTRAINT2:
- for my $c2 ( $t2->get_constraints ) {
- next if $checked_constraints{$c2};
- for my $c1 ( $t1->get_constraints ) {
- next CONSTRAINT2 if $c2->equals($c1, $case_insensitive);
- }
- if ( $c2->type eq UNIQUE ) {
- push @diffs_constraint_drops, "ALTER TABLE $t1_name DROP INDEX ".
- $c2->name.";";
- } elsif ( $target_db =~ /SQLServer/ ) {
- push @diffs_constraint_drops, "ALTER TABLE $t1_name DROP ".$c2->name.";";
- } else {
- push @diffs_constraint_drops, "ALTER TABLE $t1_name DROP ".$c2->type.
- ($c2->type eq FOREIGN_KEY ? " ".$c2->name : '').";";
- }
- }
-
- push @diffs, @diffs_index_drops, @diffs_constraint_drops,
- @diffs_table_options, @diffs_table_adds,
- @diffs_table_changes, @diffs_index_creates;
+ for my $c2 ( $t2->get_constraints ) {
+ next if $checked_constraints{$c2};
+ for my $c1 ( $t1->get_constraints ) {
+ next CONSTRAINT2 if $c2->equals($c1, $case_insensitive);
+ }
+ if ( $c2->type eq UNIQUE ) {
+ push @diffs_constraint_drops, "ALTER TABLE $t1_name DROP INDEX ".
+ $c2->name.";";
+ } elsif ( $target_db =~ /SQLServer/ ) {
+ push @diffs_constraint_drops, "ALTER TABLE $t1_name DROP ".$c2->name.";";
+ } else {
+ push @diffs_constraint_drops, "ALTER TABLE $t1_name DROP ".$c2->type.
+ ($c2->type eq FOREIGN_KEY ? " ".$c2->name : '').";";
+ }
+ }
+
+ push @diffs, @diffs_index_drops, @diffs_constraint_drops,
+ @diffs_table_options, @diffs_table_adds,
+ @diffs_table_changes, @diffs_index_creates;
}
for my $t2 ( $target_schema->get_tables ) {
my $t1 = $source_schema->get_table( $t2_name, $target_db =~ /SQLServer/ );
unless ( $t1 ) {
- if ( $target_db =~ /SQLServer/ ) {
- for my $constraint ( $t2->get_constraints ) {
- next if $constraint->type eq PRIMARY_KEY;
- push @diffs, "ALTER TABLE $t2_name DROP ".$constraint->name.";";
- }
- }
+ if ( $target_db =~ /SQLServer/ ) {
+ for my $constraint ( $t2->get_constraints ) {
+ next if $constraint->type eq PRIMARY_KEY;
+ push @diffs, "ALTER TABLE $t2_name DROP ".$constraint->name.";";
+ }
+ }
push @diffs_at_end, "DROP TABLE $t2_name;";
next;
}
my $f2_name = $t2_field->name;
my $t1_field = $t1->get_field( $f2_name );
unless ( $t1_field ) {
- my $modifier = $target_db =~ /SQLServer/ ? "COLUMN " : '';
+ my $modifier = $target_db =~ /SQLServer/ ? "COLUMN " : '';
push @diffs, "ALTER TABLE $t2_name DROP $modifier$f2_name;";
}
}
}
if ( @diffs ) {
- print join( "\n",
+ print join( "\n",
"-- Convert schema '$s2_name' to '$s1_name':\n", @diffs, "\n"
);
exit(1);
}
sub constraint_to_string {
- my $c = shift;
- my $schema = shift or die "No schema given";
- my @fields = $c->field_names or return '';
-
- if ( $c->type eq PRIMARY_KEY ) {
- if ( $target_db =~ /Oracle/ ) {
- return (defined $c->name ? 'CONSTRAINT '.$c->name.' ' : '') .
- 'PRIMARY KEY (' . join(', ', @fields). ')';
- } else {
- return 'PRIMARY KEY (' . join(', ', @fields). ')';
- }
- }
- elsif ( $c->type eq UNIQUE ) {
- if ( $target_db =~ /Oracle/ ) {
- return (defined $c->name ? 'CONSTRAINT '.$c->name.' ' : '') .
- 'UNIQUE (' . join(', ', @fields). ')';
- } else {
- return 'UNIQUE '.
- (defined $c->name ? $c->name.' ' : '').
- '(' . join(', ', @fields). ')';
- }
- }
- elsif ( $c->type eq FOREIGN_KEY ) {
- my $def = join(' ',
- map { $_ || () } 'CONSTRAINT', $c->name, 'FOREIGN KEY'
- );
-
- $def .= ' (' . join( ', ', @fields ) . ')';
-
- $def .= ' REFERENCES ' . $c->reference_table;
-
- my @rfields = map { $_ || () } $c->reference_fields;
- unless ( @rfields ) {
- my $rtable_name = $c->reference_table;
- if ( my $ref_table = $schema->get_table( $rtable_name ) ) {
- push @rfields, $ref_table->primary_key;
- }
- else {
- warn "Can't find reference table '$rtable_name' " .
- "in schema\n";
- }
- }
-
- if ( @rfields ) {
- $def .= ' (' . join( ', ', @rfields ) . ')';
- }
- else {
- warn "FK constraint on " . 'some table' . '.' .
- join('', @fields) . " has no reference fields\n";
- }
-
- if ( $c->match_type ) {
- $def .= ' MATCH ' .
- ( $c->match_type =~ /full/i ) ? 'FULL' : 'PARTIAL';
- }
-
- if ( $c->on_delete ) {
- $def .= ' ON DELETE '.join( ' ', $c->on_delete );
- }
-
- if ( $c->on_update ) {
- $def .= ' ON UPDATE '.join( ' ', $c->on_update );
- }
-
- return $def;
- }
+ my $c = shift;
+ my $schema = shift or die "No schema given";
+ my @fields = $c->field_names or return '';
+
+ if ( $c->type eq PRIMARY_KEY ) {
+ if ( $target_db =~ /Oracle/ ) {
+ return (defined $c->name ? 'CONSTRAINT '.$c->name.' ' : '') .
+ 'PRIMARY KEY (' . join(', ', @fields). ')';
+ } else {
+ return 'PRIMARY KEY (' . join(', ', @fields). ')';
+ }
+ }
+ elsif ( $c->type eq UNIQUE ) {
+ if ( $target_db =~ /Oracle/ ) {
+ return (defined $c->name ? 'CONSTRAINT '.$c->name.' ' : '') .
+ 'UNIQUE (' . join(', ', @fields). ')';
+ } else {
+ return 'UNIQUE '.
+ (defined $c->name ? $c->name.' ' : '').
+ '(' . join(', ', @fields). ')';
+ }
+ }
+ elsif ( $c->type eq FOREIGN_KEY ) {
+ my $def = join(' ',
+ map { $_ || () } 'CONSTRAINT', $c->name, 'FOREIGN KEY'
+ );
+
+ $def .= ' (' . join( ', ', @fields ) . ')';
+
+ $def .= ' REFERENCES ' . $c->reference_table;
+
+ my @rfields = map { $_ || () } $c->reference_fields;
+ unless ( @rfields ) {
+ my $rtable_name = $c->reference_table;
+ if ( my $ref_table = $schema->get_table( $rtable_name ) ) {
+ push @rfields, $ref_table->primary_key;
+ }
+ else {
+ warn "Can't find reference table '$rtable_name' " .
+ "in schema\n";
+ }
+ }
+
+ if ( @rfields ) {
+ $def .= ' (' . join( ', ', @rfields ) . ')';
+ }
+ else {
+ warn "FK constraint on " . 'some table' . '.' .
+ join('', @fields) . " has no reference fields\n";
+ }
+
+ if ( $c->match_type ) {
+ $def .= ' MATCH ' .
+ ( $c->match_type =~ /full/i ) ? 'FULL' : 'PARTIAL';
+ }
+
+ if ( $c->on_delete ) {
+ $def .= ' ON DELETE '.join( ' ', $c->on_delete );
+ }
+
+ if ( $c->on_update ) {
+ $def .= ' ON UPDATE '.join( ' ', $c->on_update );
+ }
+
+ return $def;
+ }
}
-
+
# -------------------------------------------------------------------
# Bring out number weight & measure in a year of dearth.
# William Blake
# 02111-1307 USA
# -------------------------------------------------------------------
-=head1 NAME
+=head1 NAME
sqlt-graph - Automatically create a graph from a database schema
-l|--layout Layout schema for GraphViz
("dot," "neato," "twopi"; default "dot")
- -n|--node-shape Shape of the nodes ("record," "plaintext,"
- "ellipse," "circle," "egg," "triangle," "box,"
- "diamond," "trapezium," "parallelogram," "house,"
+ -n|--node-shape Shape of the nodes ("record," "plaintext,"
+ "ellipse," "circle," "egg," "triangle," "box,"
+ "diamond," "trapezium," "parallelogram," "house,"
"hexagon," "octagon," default "record")
-o|--output Output file name (default STDOUT)
-t|--output-type Output file type ("canon", "text," "ps," "hpgl,"
--no-fields Don't show field names
--height Image height (in inches, default "11",
set to "0" to undefine)
- --width Image width (in inches, default "8.5",
+ --width Image width (in inches, default "8.5",
set to "0" to undefine)
--fontsize custom font size for node and edge labels
- --fontname name of custom font (or full path to font file) for
+ --fontname name of custom font (or full path to font file) for
node, edge, and graph labels
--nodeattr attribute name and value (in key=val syntax) for
- nodes; this option may be repeated to specify
+ nodes; this option may be repeated to specify
multiple node attributes
--edgeattr same as --nodeattr, but for edge attributes
--graphattr same as --nodeattr, but for graph attributes
--show-sizes Show column sizes for VARCHAR and CHAR fields
--show-constraints Show list of constraints for each field
-s|--skip Fields to skip in natural joins
- --skip-tables Comma-separated list of table names to exclude
+ --skip-tables Comma-separated list of table names to exclude
--skip-tables-like Comma-separated list of regexen to exclude tables
--debug Print debugging information
directed showing the direction of the relationship. If the foreign
keys are intuited via natural joins, the graph will be undirected.
-Clustering of tables allows you to group and box tables according to
-function or domain or whatever criteria you choose. The syntax for
+Clustering of tables allows you to group and box tables according to
+function or domain or whatever criteria you choose. The syntax for
clustering tables is:
cluster1=table1,table2;cluster2=table3,table4
#
# Get arguments.
#
-my (
- $layout, $node_shape, $out_file, $output_type, $db_driver, $add_color,
+my (
+ $layout, $node_shape, $out_file, $output_type, $db_driver, $add_color,
$natural_join, $join_pk_only, $skip_fields, $show_datatypes,
$show_sizes, $show_constraints, $debug, $help, $height, $width,
$no_fields, $fontsize, $fontname, $skip_tables, $skip_tables_like,
pod2usage( -message => "No db driver specified" ) unless $db_driver;
pod2usage( -message => 'No input file' ) unless @files;
-my $translator = SQL::Translator->new(
+my $translator = SQL::Translator->new(
from => $db_driver,
to => 'GraphViz',
debug => $debug || 0,
=head1 DESCRIPTION
Place this script in your "cgi-bin" directory and point your browser
-to it. This script is meant to be a simple graphical interface to
+to it. This script is meant to be a simple graphical interface to
all the parsers and producers of SQL::Translator.
=cut
my $output_type = $producer eq 'Diagram'
? $q->param('diagram_output_type')
: $producer eq 'GraphViz'
- ? $q->param('graphviz_output_type')
+ ? $q->param('graphviz_output_type')
: ''
;
- my $t = SQL::Translator->new(
+ my $t = SQL::Translator->new(
from => $q->param('parser'),
producer_args => {
add_drop_table => $q->param('add_drop_table'),
output_type => $output_type,
title => $q->param('title') || 'Schema',
- natural_join => $q->param('natural_join') eq 'no' ? 0 : 1,
- join_pk_only => $q->param('natural_join') eq 'pk_only'
+ natural_join => $q->param('natural_join') eq 'no' ? 0 : 1,
+ join_pk_only => $q->param('natural_join') eq 'pk_only'
? 1 : 0,
add_color => $q->param('add_color'),
skip_fields => $q->param('skip_fields'),
my $q = shift;
my $title = 'SQL::Translator';
- print $q->header,
+ print $q->header,
$q->start_html( -title => $title ),
$q->h1( qq[<a href="http://sqlfairy.sourceforge.net">$title</a>] ),
$q->start_form(-enctype => 'multipart/form-data'),
$q->table( { -border => 1 },
- $q->Tr(
+ $q->Tr(
$q->td( [
'Upload your schema file:',
$q->filefield( -name => 'schema_file'),
] ),
),
- $q->Tr(
+ $q->Tr(
$q->td( [
'Or paste your schema here:',
- $q->textarea(
- -name => 'schema',
- -rows => 5,
+ $q->textarea(
+ -name => 'schema',
+ -rows => 5,
-columns => 60,
),
] ),
),
- $q->Tr(
+ $q->Tr(
$q->td( [
'Parser:',
$q->radio_group(
-name => 'parser',
- -values => [ qw( MySQL PostgreSQL Oracle
- Sybase Excel XML-SQLFairy xSV
+ -values => [ qw( MySQL PostgreSQL Oracle
+ Sybase Excel XML-SQLFairy xSV
) ],
-default => 'MySQL',
-rows => 3,
),
] ),
),
- $q->Tr(
+ $q->Tr(
$q->td( [
'Producer:',
$q->radio_group(
),
] ),
),
- $q->Tr(
+ $q->Tr(
$q->td(
{ -colspan => 2, -align => 'center' },
- $q->submit(
- -name => 'submit',
+ $q->submit(
+ -name => 'submit',
-value => 'Submit',
)
),
),
- $q->Tr(
- $q->th(
- { align => 'left', bgcolor => 'lightgrey', colspan => 2 },
- 'General Options:'
+ $q->Tr(
+ $q->th(
+ { align => 'left', bgcolor => 'lightgrey', colspan => 2 },
+ 'General Options:'
),
),
- $q->Tr(
+ $q->Tr(
$q->td( [
'Validate Schema:',
$q->radio_group(
-name => 'validate',
-values => [ 1, 0 ],
- -labels => {
- 1 => 'Yes',
- 0 => 'No'
+ -labels => {
+ 1 => 'Yes',
+ 0 => 'No'
},
-default => 0,
-rows => 2,
),
] ),
),
- $q->Tr(
- $q->th(
- { align => 'left', bgcolor => 'lightgrey', colspan => 2 },
- 'DB Producer Options:'
+ $q->Tr(
+ $q->th(
+ { align => 'left', bgcolor => 'lightgrey', colspan => 2 },
+ 'DB Producer Options:'
),
),
- $q->Tr(
+ $q->Tr(
$q->td( [
'Add "DROP TABLE" statements:',
$q->radio_group(
-name => 'add_drop_table',
-values => [ 1, 0 ],
- -labels => {
- 1 => 'Yes',
- 0 => 'No'
+ -labels => {
+ 1 => 'Yes',
+ 0 => 'No'
},
-default => 0,
-rows => 2,
),
] ),
),
- $q->Tr(
+ $q->Tr(
$q->td( [
'Include comments:',
$q->radio_group(
-name => 'comments',
-values => [ 1, 0 ],
- -labels => {
- 1 => 'Yes',
- 0 => 'No'
+ -labels => {
+ 1 => 'Yes',
+ 0 => 'No'
},
-default => 1,
-rows => 2,
),
] ),
),
- $q->Tr(
- $q->th(
- { align => 'left', bgcolor => 'lightgrey', colspan => 2 },
- 'HTML/POD/Diagram Producer Options:'
+ $q->Tr(
+ $q->th(
+ { align => 'left', bgcolor => 'lightgrey', colspan => 2 },
+ 'HTML/POD/Diagram Producer Options:'
),
),
- $q->Tr(
+ $q->Tr(
$q->td( [
'Title:',
$q->textfield('title'),
] ),
),
- $q->Tr(
- $q->th(
- { align => 'left', bgcolor => 'lightgrey', colspan => 2 },
- 'TTSchema Producer Options:'
+ $q->Tr(
+ $q->th(
+ { align => 'left', bgcolor => 'lightgrey', colspan => 2 },
+ 'TTSchema Producer Options:'
),
),
- $q->Tr(
+ $q->Tr(
$q->td( [
'Template:',
$q->filefield( -name => 'template'),
] ),
),
- $q->Tr(
- $q->th(
- { align => 'left', bgcolor => 'lightgrey', colspan => 2 },
+ $q->Tr(
+ $q->th(
+ { align => 'left', bgcolor => 'lightgrey', colspan => 2 },
'Graphical Producer Options'
),
),
- $q->Tr(
+ $q->Tr(
$q->td( [
'Perform Natural Joins:',
$q->radio_group(
),
] ),
),
- $q->Tr(
+ $q->Tr(
$q->td( [
'Skip These Fields in Natural Joins:',
$q->textarea(
),
] ),
),
- $q->Tr(
+ $q->Tr(
$q->td( [
'Show Only Foreign Keys:',
$q->radio_group(
),
] ),
),
- $q->Tr(
+ $q->Tr(
$q->td( [
'Add Color:',
$q->radio_group(
-name => 'add_color',
-values => [ 1, 0 ],
- -labels => {
- 1 => 'Yes',
- 0 => 'No'
+ -labels => {
+ 1 => 'Yes',
+ 0 => 'No'
},
-default => 1,
-rows => 2,
),
] ),
),
- $q->Tr(
+ $q->Tr(
$q->td( [
'Show Field Names:',
$q->radio_group(
),
] ),
),
- $q->Tr(
- $q->th(
- { align => 'left', bgcolor => 'lightgrey', colspan => 2 },
+ $q->Tr(
+ $q->th(
+ { align => 'left', bgcolor => 'lightgrey', colspan => 2 },
'Diagram Producer Options'
),
),
- $q->Tr(
+ $q->Tr(
$q->td( [
'Output Type:',
$q->radio_group(
),
] ),
),
- $q->Tr(
+ $q->Tr(
$q->td( [
'Font Size:',
$q->radio_group(
),
] ),
),
- $q->Tr(
+ $q->Tr(
$q->td( [
'Number of Columns:',
$q->textfield('no_columns'),
] ),
),
- $q->Tr(
- $q->th(
- { align => 'left', bgcolor => 'lightgrey', colspan => 2 },
+ $q->Tr(
+ $q->th(
+ { align => 'left', bgcolor => 'lightgrey', colspan => 2 },
'GraphViz Producer Options'
),
),
- $q->Tr(
+ $q->Tr(
$q->td( [
'Output Type:',
$q->radio_group(
),
] ),
),
- $q->Tr(
+ $q->Tr(
$q->td( [
'Layout:',
$q->radio_group(
),
] ),
),
- $q->Tr(
+ $q->Tr(
$q->td( [
'Node Shape:',
$q->radio_group(
-name => 'node_shape',
- -values => [ qw( record plaintext ellipse
- circle egg triangle box diamond trapezium
- parallelogram house hexagon octagon
+ -values => [ qw( record plaintext ellipse
+ circle egg triangle box diamond trapezium
+ parallelogram house hexagon octagon
) ],
-default => 'record',
-rows => 4,
),
] ),
),
- $q->Tr(
+ $q->Tr(
$q->td( [
'Height:',
$q->textfield( -name => 'height' ),
] ),
),
- $q->Tr(
+ $q->Tr(
$q->td( [
'Width:',
$q->textfield( -name => 'width' ),
] ),
),
- $q->Tr(
- $q->th(
- { align => 'left', bgcolor => 'lightgrey', colspan => 2 },
- 'XML Producer Options:'
+ $q->Tr(
+ $q->th(
+ { align => 'left', bgcolor => 'lightgrey', colspan => 2 },
+ 'XML Producer Options:'
),
),
- $q->Tr(
+ $q->Tr(
$q->td( [
'Use attributes for values:',
$q->radio_group(
-name => 'attrib-values',
-values => [ 1, 0 ],
- -labels => {
- 1 => 'Yes',
- 0 => 'No'
+ -labels => {
+ 1 => 'Yes',
+ 0 => 'No'
},
-default => 0,
-rows => 2,
),
] ),
),
- $q->Tr(
+ $q->Tr(
$q->td( [
'Emit Empty Tags:',
$q->radio_group(
-name => 'emit-empty-tags',
-values => [ 1, 0 ],
- -labels => {
- 1 => 'Yes',
- 0 => 'No'
+ -labels => {
+ 1 => 'Yes',
+ 0 => 'No'
},
-default => 0,
-rows => 2,
),
] ),
),
- $q->Tr(
- $q->th(
- { align => 'left', bgcolor => 'lightgrey', colspan => 2 },
+ $q->Tr(
+ $q->th(
+ { align => 'left', bgcolor => 'lightgrey', colspan => 2 },
'xSV Parser Options'
),
),
- $q->Tr(
+ $q->Tr(
$q->td( [
'Field Separator:',
$q->textfield( -name => 'fs' ),
] ),
),
- $q->Tr(
+ $q->Tr(
$q->td( [
'Record Separator:',
$q->textfield( -name => 'rs' ),
] ),
),
- $q->Tr(
+ $q->Tr(
$q->td( [
'Trim Whitespace Around Fields:',
$q->radio_group(
),
] ),
),
- $q->Tr(
+ $q->Tr(
$q->td( [
'Scan Fields for Data Type:',
$q->radio_group(
),
] ),
),
- $q->Tr(
+ $q->Tr(
$q->td(
{ -colspan => 2, -align => 'center' },
- $q->submit(
- -name => 'submit',
+ $q->submit(
+ -name => 'submit',
-value => 'Submit',
)
),
{
my $tr = SQL::Translator->new;
- my $data = parse($tr,
+ my $data = parse($tr,
q[
CREATE TABLE `check` (
- check_id int(7) unsigned zerofill NOT NULL default '0000000'
+ check_id int(7) unsigned zerofill NOT NULL default '0000000'
auto_increment primary key,
successful date NOT NULL default '0000-00-00',
unsuccessful date default '0000-00-00',
) TYPE=MyISAM PACK_KEYS=1;
]
);
-
+
my $schema = $tr->schema;
is( $schema->is_valid, 1, 'Schema is valid' );
my @tables = $schema->get_tables;
{
my $tr = SQL::Translator->new;
- my $data = parse($tr,
+ my $data = parse($tr,
q[
CREATE TABLE orders (
order_id integer NOT NULL auto_increment,
is( $f2->default_value, undef, 'Default value is undefined' );
my $f3 = shift @fields;
- is( $f3->name, 'billing_address_id',
+ is( $f3->name, 'billing_address_id',
'Third field name is "billing_address_id"' );
is( $f3->data_type, 'int', 'Type is "int"' );
is( $f3->size, 11, 'Size is "11"' );
my $f4 = shift @fields;
- is( $f4->name, 'shipping_address_id',
+ is( $f4->name, 'shipping_address_id',
'Fourth field name is "shipping_address_id"' );
is( $f4->data_type, 'int', 'Type is "int"' );
is( $f4->size, 11, 'Size is "11"' );
my $i2 = shift @indices;
is( $i2->type, NORMAL, 'Second index is normal' );
- is( join(',', $i2->fields), 'billing_address_id',
+ is( join(',', $i2->fields), 'billing_address_id',
'Index is on "billing_address_id"' );
my $i3 = shift @indices;
is( $i3->type, NORMAL, 'Third index is normal' );
- is( join(',', $i3->fields), 'shipping_address_id',
+ is( join(',', $i3->fields), 'shipping_address_id',
'Index is on "shipping_address_id"' );
my $i4 = shift @indices;
is( $i4->type, NORMAL, 'Third index is normal' );
- is( join(',', $i4->fields), 'member_id,store_id',
+ is( join(',', $i4->fields), 'member_id,store_id',
'Index is on "member_id,store_id"' );
my @constraints = $t1->get_constraints;
my $c3 = shift @constraints;
is( $c3->type, FOREIGN_KEY, 'Constraint is a FK' );
- is( join(',', $c3->fields), 'billing_address_id',
+ is( join(',', $c3->fields), 'billing_address_id',
'Constraint is on "billing_address_id"' );
is( $c3->reference_table, 'address', 'To table "address"' );
- is( join(',', $c3->reference_fields), 'address_id',
+ is( join(',', $c3->reference_fields), 'address_id',
'To field "address_id"' );
my $c4 = shift @constraints;
is( $c4->type, FOREIGN_KEY, 'Constraint is a FK' );
- is( join(',', $c4->fields), 'shipping_address_id',
+ is( join(',', $c4->fields), 'shipping_address_id',
'Constraint is on "shipping_address_id"' );
is( $c4->reference_table, 'address', 'To table "address"' );
- is( join(',', $c4->reference_fields), 'address_id',
+ is( join(',', $c4->reference_fields), 'address_id',
'To field "address_id"' );
my $c5 = shift @constraints;
is( $c5->type, FOREIGN_KEY, 'Constraint is a FK' );
is( join(',', $c5->fields), 'store_id', 'Constraint is on "store_id"' );
is( $c5->reference_table, 'store', 'To table "store"' );
- is( join(',', map { $_ || '' } $c5->reference_fields), '',
+ is( join(',', map { $_ || '' } $c5->reference_fields), '',
'No reference fields defined' );
my $t2 = shift @tables;
#
{
my $tr = SQL::Translator->new;
- my $data = parse($tr,
+ my $data = parse($tr,
q[
USE database_name;
#
{
my $tr = SQL::Translator->new(parser_args => {mysql_parser_version => 50003});
- my $data = parse($tr,
+ my $data = parse($tr,
q[
- DELIMITER ;;
+ DELIMITER ;;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;;
- /*!50003 CREATE */ /*!50017 DEFINER=`cmdomain`@`localhost` */
- /*!50003 TRIGGER `acl_entry_insert` BEFORE INSERT ON `acl_entry`
- FOR EACH ROW SET NEW.dateCreated = CONVERT_TZ(SYSDATE(),'SYSTEM','+0:00'),
- NEW.dateModified = CONVERT_TZ(SYSDATE(),'SYSTEM','+0:00') */;;
+ /*!50003 CREATE */ /*!50017 DEFINER=`cmdomain`@`localhost` */
+ /*!50003 TRIGGER `acl_entry_insert` BEFORE INSERT ON `acl_entry`
+ FOR EACH ROW SET NEW.dateCreated = CONVERT_TZ(SYSDATE(),'SYSTEM','+0:00'),
+ NEW.dateModified = CONVERT_TZ(SYSDATE(),'SYSTEM','+0:00') */;;
- DELIMITER ;
+ DELIMITER ;
CREATE TABLE one (
`op` varchar(255) character set latin1 collate latin1_bin default NULL,
`last_modified` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
) TYPE=INNODB DEFAULT CHARSET=latin1;
- /*!50001 CREATE ALGORITHM=UNDEFINED */
- /*!50013 DEFINER=`cmdomain`@`localhost` SQL SECURITY DEFINER */
- /*! VIEW `vs_asset` AS
- select `a`.`asset_id` AS `asset_id`,`a`.`fq_name` AS `fq_name`,
- `cfgmgmt_mig`.`ap_extract_folder`(`a`.`fq_name`) AS `folder_name`,
- `cfgmgmt_mig`.`ap_extract_asset`(`a`.`fq_name`) AS `asset_name`,
- `a`.`annotation` AS `annotation`,`a`.`asset_type` AS `asset_type`,
- `a`.`foreign_asset_id` AS `foreign_asset_id`,
- `a`.`foreign_asset_id2` AS `foreign_asset_id2`,`a`.`dateCreated` AS `date_created`,
- `a`.`dateModified` AS `date_modified`,`a`.`container_id` AS `container_id`,
- `a`.`creator_id` AS `creator_id`,`a`.`modifier_id` AS `modifier_id`,
- `m`.`user_id` AS `user_access`
- from (`asset` `a` join `M_ACCESS_CONTROL` `m` on((`a`.`acl_id` = `m`.`acl_id`))) */;
- DELIMITER ;;
- /*!50001 CREATE */
- /*! VIEW `vs_asset2` AS
- select `a`.`asset_id` AS `asset_id`,`a`.`fq_name` AS `fq_name`,
- `cfgmgmt_mig`.`ap_extract_folder`(`a`.`fq_name`) AS `folder_name`,
- `cfgmgmt_mig`.`ap_extract_asset`(`a`.`fq_name`) AS `asset_name`,
- `a`.`annotation` AS `annotation`,`a`.`asset_type` AS `asset_type`,
- `a`.`foreign_asset_id` AS `foreign_asset_id`,
- `a`.`foreign_asset_id2` AS `foreign_asset_id2`,`a`.`dateCreated` AS `date_created`,
- `a`.`dateModified` AS `date_modified`,`a`.`container_id` AS `container_id`,
- `a`.`creator_id` AS `creator_id`,`a`.`modifier_id` AS `modifier_id`,
- `m`.`user_id` AS `user_access`
- from (`asset` `a` join `M_ACCESS_CONTROL` `m` on((`a`.`acl_id` = `m`.`acl_id`))) */;
- DELIMITER ;;
- /*!50001 CREATE OR REPLACE */
- /*! VIEW `vs_asset3` AS
- select `a`.`asset_id` AS `asset_id`,`a`.`fq_name` AS `fq_name`,
- `cfgmgmt_mig`.`ap_extract_folder`(`a`.`fq_name`) AS `folder_name`,
- `cfgmgmt_mig`.`ap_extract_asset`(`a`.`fq_name`) AS `asset_name`,
- `a`.`annotation` AS `annotation`,`a`.`asset_type` AS `asset_type`,
- `a`.`foreign_asset_id` AS `foreign_asset_id`,
- `a`.`foreign_asset_id2` AS `foreign_asset_id2`,`a`.`dateCreated` AS `date_created`,
- `a`.`dateModified` AS `date_modified`,`a`.`container_id` AS `container_id`,
- `a`.`creator_id` AS `creator_id`,`a`.`modifier_id` AS `modifier_id`,
- `m`.`user_id` AS `user_access`
- from (`asset` `a` join `M_ACCESS_CONTROL` `m` on((`a`.`acl_id` = `m`.`acl_id`))) */;
- DELIMITER ;;
- /*!50003 CREATE*/ /*!50020 DEFINER=`cmdomain`@`localhost`*/ /*!50003 FUNCTION `ap_from_millitime_nullable`( millis_since_1970 BIGINT ) RETURNS timestamp
- DETERMINISTIC
- BEGIN
- DECLARE rval TIMESTAMP;
- IF ( millis_since_1970 = 0 )
- THEN
- SET rval = NULL;
- ELSE
- SET rval = FROM_UNIXTIME( millis_since_1970 / 1000 );
- END IF;
- RETURN rval;
- END */;;
- /*!50003 CREATE*/ /*!50020 DEFINER=`cmdomain`@`localhost`*/ /*!50003 PROCEDURE `sp_update_security_acl`(IN t_acl_id INTEGER)
- BEGIN
- DECLARE hasMoreRows BOOL DEFAULT TRUE;
- DECLARE t_group_id INT;
- DECLARE t_user_id INT ;
- DECLARE t_user_name VARCHAR (512) ;
- DECLARE t_message VARCHAR (512) ;
-
- DROP TABLE IF EXISTS group_acl;
- DROP TABLE IF EXISTS user_group;
- DELETE FROM M_ACCESS_CONTROL WHERE acl_id = t_acl_id;
-
- CREATE TEMPORARY TABLE group_acl SELECT DISTINCT p.id group_id, d.acl_id acl_id
- FROM asset d, acl_entry e, alterpoint_principal p
- WHERE d.acl_id = e.acl
- AND p.id = e.principal AND d.acl_id = t_acl_id;
-
- CREATE TEMPORARY TABLE user_group SELECT a.id user_id, a.name user_name, c.id group_id
- FROM alterpoint_principal a, groups_for_user b, alterpoint_principal c
- WHERE a.id = b.user_ref AND b.elt = c.id;
-
- INSERT INTO M_ACCESS_CONTROL SELECT DISTINCT group_acl.group_id, group_acl.acl_id, user_group.user_id, user_group.user_name
- FROM group_acl, user_group
- WHERE group_acl.group_id = user_group.group_id ;
- END */;;
+ /*!50001 CREATE ALGORITHM=UNDEFINED */
+ /*!50013 DEFINER=`cmdomain`@`localhost` SQL SECURITY DEFINER */
+ /*! VIEW `vs_asset` AS
+ select `a`.`asset_id` AS `asset_id`,`a`.`fq_name` AS `fq_name`,
+ `cfgmgmt_mig`.`ap_extract_folder`(`a`.`fq_name`) AS `folder_name`,
+ `cfgmgmt_mig`.`ap_extract_asset`(`a`.`fq_name`) AS `asset_name`,
+ `a`.`annotation` AS `annotation`,`a`.`asset_type` AS `asset_type`,
+ `a`.`foreign_asset_id` AS `foreign_asset_id`,
+ `a`.`foreign_asset_id2` AS `foreign_asset_id2`,`a`.`dateCreated` AS `date_created`,
+ `a`.`dateModified` AS `date_modified`,`a`.`container_id` AS `container_id`,
+ `a`.`creator_id` AS `creator_id`,`a`.`modifier_id` AS `modifier_id`,
+ `m`.`user_id` AS `user_access`
+ from (`asset` `a` join `M_ACCESS_CONTROL` `m` on((`a`.`acl_id` = `m`.`acl_id`))) */;
+ DELIMITER ;;
+ /*!50001 CREATE */
+ /*! VIEW `vs_asset2` AS
+ select `a`.`asset_id` AS `asset_id`,`a`.`fq_name` AS `fq_name`,
+ `cfgmgmt_mig`.`ap_extract_folder`(`a`.`fq_name`) AS `folder_name`,
+ `cfgmgmt_mig`.`ap_extract_asset`(`a`.`fq_name`) AS `asset_name`,
+ `a`.`annotation` AS `annotation`,`a`.`asset_type` AS `asset_type`,
+ `a`.`foreign_asset_id` AS `foreign_asset_id`,
+ `a`.`foreign_asset_id2` AS `foreign_asset_id2`,`a`.`dateCreated` AS `date_created`,
+ `a`.`dateModified` AS `date_modified`,`a`.`container_id` AS `container_id`,
+ `a`.`creator_id` AS `creator_id`,`a`.`modifier_id` AS `modifier_id`,
+ `m`.`user_id` AS `user_access`
+ from (`asset` `a` join `M_ACCESS_CONTROL` `m` on((`a`.`acl_id` = `m`.`acl_id`))) */;
+ DELIMITER ;;
+ /*!50001 CREATE OR REPLACE */
+ /*! VIEW `vs_asset3` AS
+ select `a`.`asset_id` AS `asset_id`,`a`.`fq_name` AS `fq_name`,
+ `cfgmgmt_mig`.`ap_extract_folder`(`a`.`fq_name`) AS `folder_name`,
+ `cfgmgmt_mig`.`ap_extract_asset`(`a`.`fq_name`) AS `asset_name`,
+ `a`.`annotation` AS `annotation`,`a`.`asset_type` AS `asset_type`,
+ `a`.`foreign_asset_id` AS `foreign_asset_id`,
+ `a`.`foreign_asset_id2` AS `foreign_asset_id2`,`a`.`dateCreated` AS `date_created`,
+ `a`.`dateModified` AS `date_modified`,`a`.`container_id` AS `container_id`,
+ `a`.`creator_id` AS `creator_id`,`a`.`modifier_id` AS `modifier_id`,
+ `m`.`user_id` AS `user_access`
+ from (`asset` `a` join `M_ACCESS_CONTROL` `m` on((`a`.`acl_id` = `m`.`acl_id`))) */;
+ DELIMITER ;;
+ /*!50003 CREATE*/ /*!50020 DEFINER=`cmdomain`@`localhost`*/ /*!50003 FUNCTION `ap_from_millitime_nullable`( millis_since_1970 BIGINT ) RETURNS timestamp
+ DETERMINISTIC
+ BEGIN
+ DECLARE rval TIMESTAMP;
+ IF ( millis_since_1970 = 0 )
+ THEN
+ SET rval = NULL;
+ ELSE
+ SET rval = FROM_UNIXTIME( millis_since_1970 / 1000 );
+ END IF;
+ RETURN rval;
+ END */;;
+ /*!50003 CREATE*/ /*!50020 DEFINER=`cmdomain`@`localhost`*/ /*!50003 PROCEDURE `sp_update_security_acl`(IN t_acl_id INTEGER)
+ BEGIN
+ DECLARE hasMoreRows BOOL DEFAULT TRUE;
+ DECLARE t_group_id INT;
+ DECLARE t_user_id INT ;
+ DECLARE t_user_name VARCHAR (512) ;
+ DECLARE t_message VARCHAR (512) ;
+
+ DROP TABLE IF EXISTS group_acl;
+ DROP TABLE IF EXISTS user_group;
+ DELETE FROM M_ACCESS_CONTROL WHERE acl_id = t_acl_id;
+
+ CREATE TEMPORARY TABLE group_acl SELECT DISTINCT p.id group_id, d.acl_id acl_id
+ FROM asset d, acl_entry e, alterpoint_principal p
+ WHERE d.acl_id = e.acl
+ AND p.id = e.principal AND d.acl_id = t_acl_id;
+
+ CREATE TEMPORARY TABLE user_group SELECT a.id user_id, a.name user_name, c.id group_id
+ FROM alterpoint_principal a, groups_for_user b, alterpoint_principal c
+ WHERE a.id = b.user_ref AND b.elt = c.id;
+
+ INSERT INTO M_ACCESS_CONTROL SELECT DISTINCT group_acl.group_id, group_acl.acl_id, user_group.user_id, user_group.user_name
+ FROM group_acl, user_group
+ WHERE group_acl.group_id = user_group.group_id ;
+ END */;;
]
) or die $tr->error;
is(scalar @fields, 2, 'Right number of fields (2) on table one');
my $tableTypeFound = 0;
my $charsetFound = 0;
- for my $t1_option_ref ( $table1->options ) {
- my($key, $value) = %{$t1_option_ref};
- if ( $key eq 'TYPE' ) {
- is($value, 'INNODB', 'Table has right table type option' );
- $tableTypeFound = 1;
- } elsif ( $key eq 'CHARACTER SET' ) {
- is($value, 'latin1', 'Table has right character set option' );
- $charsetFound = 1;
- }
- }
- fail('Table did not have a type option') unless $tableTypeFound;
- fail('Table did not have a character set option') unless $charsetFound;
+ for my $t1_option_ref ( $table1->options ) {
+ my($key, $value) = %{$t1_option_ref};
+ if ( $key eq 'TYPE' ) {
+ is($value, 'INNODB', 'Table has right table type option' );
+ $tableTypeFound = 1;
+ } elsif ( $key eq 'CHARACTER SET' ) {
+ is($value, 'latin1', 'Table has right character set option' );
+ $charsetFound = 1;
+ }
+ }
+ fail('Table did not have a type option') unless $tableTypeFound;
+ fail('Table did not have a character set option') unless $charsetFound;
my $t1f1 = shift @fields;
is( $t1f1->data_type, 'varchar', 'Field is a varchar' );
is_deeply(
$t1f2->default_value,
\'CURRENT_TIMESTAMP',
- 'Field has right default value'
+ 'Field has right default value'
);
is( $t1f2->extra('on update'), 'CURRENT_TIMESTAMP', 'Field has right on update qualifier' );
is( scalar @procs, 2, 'Right number of procedures (2)' );
my $proc1 = shift @procs;
is( $proc1->name, 'ap_from_millitime_nullable', 'Found "ap_from_millitime_nullable" procedure' );
- like($proc1->sql, qr/CREATE FUNCTION ap_from_millitime_nullable/, "Detected procedure ap_from_millitime_nullable");
+ like($proc1->sql, qr/CREATE FUNCTION ap_from_millitime_nullable/, "Detected procedure ap_from_millitime_nullable");
my $proc2 = shift @procs;
is( $proc2->name, 'sp_update_security_acl', 'Found "sp_update_security_acl" procedure' );
- like($proc2->sql, qr/CREATE PROCEDURE sp_update_security_acl/, "Detected procedure sp_update_security_acl");
+ like($proc2->sql, qr/CREATE PROCEDURE sp_update_security_acl/, "Detected procedure sp_update_security_acl");
}
# Tests for collate table option
{
my $tr = SQL::Translator->new(parser_args => {mysql_parser_version => 50003});
- my $data = parse($tr,
+ my $data = parse($tr,
q[
CREATE TABLE test ( id int ) DEFAULT CHARACTER SET latin1 COLLATE latin1_bin;
- ] );
+ ] );
my $schema = $tr->schema;
is( $schema->is_valid, 1, 'Schema is valid' );
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 \'
- # however in mysql 5.x (and probably other previous versions) still actually outputs that as ''
+ # however in mysql 5.x (and probably other previous versions) still actually outputs that as ''
is( $f3->name, 'user', 'Second field name is "user"' );
is( $f3->data_type, 'varchar', 'Type is "varchar"' );
is( $f3->size, 20, 'Size is "20"' );
};
BEGIN {
- maybe_plan(2,
+ maybe_plan(2,
'SQL::Translator::Parser::MySQL',
'SQL::Translator::Producer::XML::SQLFairy');
}
require XML::Parser;
};
if ($@) {
- skip "Can't load XML::Parser" => 1;
+ skip "Can't load XML::Parser" => 1;
}
# Can't get XML::Parser::parsestring to do Useful Things
use Test::SQL::Translator qw(maybe_plan);
BEGIN {
- maybe_plan(1,
+ maybe_plan(1,
'SQL::Translator::Parser::MySQL',
'SQL::Translator::Producer::PostgreSQL');
}
my $create = q|
--- The cvterm module design is based on the ontology
+-- The cvterm module design is based on the ontology
-- ================================================
-- TABLE: cv
);
create index cvterm_idx1 on cvterm (cv_id);
-- the primary dbxref for this term. Other dbxrefs may be cvterm_dbxref
--- The unique key on termname, termtype_id ensures that all terms are
+-- The unique key on termname, termtype_id ensures that all terms are
-- unique within a given cv
'A human-readable text definition';
COMMENT ON COLUMN cvterm.dbxref_id IS
'A human-readable text definition';
-COMMENT ON INDEX cvterm_c1 IS
+COMMENT ON INDEX cvterm_c1 IS
'the OBO identifier is globally unique';
unique(cvterm_id, termsynonym)
);
--- The table "cvterm_synonym" doesn't exist, so
+-- The table "cvterm_synonym" doesn't exist, so
-- creating an index on it screws things up!
-- create index cvterm_synonym_idx1 on cvterm_synonym (cvterm_id);
cvterm_id int not null,
foreign key (cvterm_id) references cvterm (cvterm_id),
cvterm_geom geometry,
- constraint "enforce_dims_cvterm_geom" CHECK ((st_ndims(cvterm_geom) = 2)),
- constraint "enforce_srid_cvterm_geom" CHECK ((st_srid(cvterm_geom) = -1)),
- constraint "enforce_geotype_cvterm_geom" CHECK ((geometrytype(cvterm_geom) = 'POINT'::text OR cvterm_geom IS NULL)),
+ constraint "enforce_dims_cvterm_geom" CHECK ((st_ndims(cvterm_geom) = 2)),
+ constraint "enforce_srid_cvterm_geom" CHECK ((st_srid(cvterm_geom) = -1)),
+ constraint "enforce_geotype_cvterm_geom" CHECK ((geometrytype(cvterm_geom) = 'POINT'::text OR cvterm_geom IS NULL)),
unique(cvterm_id)
);
my $tmp = mktemp('sqlXXXXX');
-ok(-e $sqlt_diagram);
+ok(-e $sqlt_diagram);
my @cmd = ($^X, $sqlt_diagram, "-d", "MySQL", "-o", $tmp, $test_data);
eval { system(@cmd); };
ok(!$@ && ($? == 0));
-ok(-e $tmp);
+ok(-e $tmp);
eval { unlink $tmp; };
maybe_plan(31, 'SQL::Translator::Parser::Excel');
SQL::Translator::Parser::Excel->import('parse');
}
-
+
my $tr = SQL::Translator->new(parser => "Excel");
my $t = $tr->translate(filename => "t/data/Excel/t.xls");
my $schema = $tr->schema;
my $f4 = shift @fields;
TODO: {
eval { require Spreadsheet::ParseExcel };
- todo_skip "Bug in Spreadsheet::ParseExcel, http://rt.cpan.org/Public/Bug/Display.html?id=39892", 4
+ todo_skip "Bug in Spreadsheet::ParseExcel, http://rt.cpan.org/Public/Bug/Display.html?id=39892", 4
if ( $Spreadsheet::ParseExcel::VERSION > 0.32 and $Spreadsheet::ParseExcel::VERSION < 0.41 );
is( $f4->name, 'math', 'Fourth field name is "math"' );
is( $f6->is_primary_key, 0, 'Field is not PK' );
my $f7 = shift @fields;
-is( $f7->name, 'silly_field_with_random_characters',
+is( $f7->name, 'silly_field_with_random_characters',
'Seventh field name is "silly_field_with_random_characters"' );
is( lc $f7->data_type, 'char', 'Data type is "CHAR"' );
is( $f7->size, 11, 'Size is "11"' );
#
# Schema
#
- my $schema = SQL::Translator::Schema->new(
+ my $schema = SQL::Translator::Schema->new(
name => 'foo',
database => 'MySQL',
);
is( $schema->name('bar'), 'bar', 'Schema name changed to "bar"' );
is( $schema->database, 'MySQL', 'Schema database is "MySQL"' );
- is( $schema->database('PostgreSQL'), 'PostgreSQL',
+ is( $schema->database('PostgreSQL'), 'PostgreSQL',
'Schema database changed to "PostgreSQL"' );
is( $schema->is_valid, undef, 'Schema not valid...' );
my $foo_table = $schema->add_table(name => 'foo') or warn $schema->error;
isa_ok( $foo_table, 'SQL::Translator::Schema::Table', 'Table "foo"' );
- my $bar_table = SQL::Translator::Schema::Table->new( name => 'bar' ) or
+ my $bar_table = SQL::Translator::Schema::Table->new( name => 'bar' ) or
warn SQL::Translator::Schema::Table->error;
$bar_table = $schema->add_table( $bar_table );
isa_ok( $bar_table, 'SQL::Translator::Schema::Table', 'Table "bar"' );
$schema = $bar_table->schema( $schema );
isa_ok( $schema, 'SQL::Translator::Schema', 'Schema' );
- is( $bar_table->name('foo'), undef,
+ is( $bar_table->name('foo'), undef,
q[Can't change name of table "bar" to "foo"...]);
- like( $bar_table->error, qr/can't use table name/i,
+ like( $bar_table->error, qr/can't use table name/i,
q[...because "foo" exists] );
my $redundant_table = $schema->add_table(name => 'foo');
is( $redundant_table, undef, qq[Can't create another "foo" table...] );
- like( $schema->error, qr/can't use table name/i,
+ like( $schema->error, qr/can't use table name/i,
'... because "foo" exists' );
$redundant_table = $schema->add_table(name => '');
#
# New table with args
#
- my $person_table = $schema->add_table(
- name => 'person',
+ my $person_table = $schema->add_table(
+ name => 'person',
comments => 'foo',
);
is( $person_table->name, 'person', 'Table name is "person"' );
is( $person_table->is_valid, undef, 'Table is not yet valid' );
is( $person_table->comments, 'foo', 'Comments = "foo"' );
- is( join(',', $person_table->comments('bar')), 'foo,bar',
+ is( join(',', $person_table->comments('bar')), 'foo,bar',
'Table comments = "foo,bar"' );
is( $person_table->comments, "foo\nbar", 'Table comments = "foo,bar"' );
#
# Field default new
#
- my $f1 = $person_table->add_field(name => 'foo') or
+ my $f1 = $person_table->add_field(name => 'foo') or
warn $person_table->error;
isa_ok( $f1, 'SQL::Translator::Schema::Field', 'Field' );
is( $f1->name, 'foo', 'Field name is "foo"' );
is( $f2->is_nullable('0'), 0, 'Field cannot be NULL' );
is( $f2->default_value(''), '', 'Field default is empty string' );
is( $f2->comments, 'foo', 'Field comment = "foo"' );
- is( join(',', $f2->comments('bar')), 'foo,bar',
+ is( join(',', $f2->comments('bar')), 'foo,bar',
'Field comment = "foo,bar"' );
is( $f2->comments, "foo\nbar", 'Field comment = "foo,bar"' );
my $redundant_field = $person_table->add_field(name => 'f2');
is( $redundant_field, undef, qq[Didn't create another "f2" field...] );
- like( $person_table->error, qr/can't use field/i,
+ like( $person_table->error, qr/can't use field/i,
'... because it exists' );
$redundant_field = $person_table->add_field(name => '');
my @indices = $person_table->get_indices;
is( scalar @indices, 0, 'No indices' );
like( $person_table->error, qr/no indices/i, 'Error for no indices' );
- my $index1 = $person_table->add_index( name => "foo" )
+ my $index1 = $person_table->add_index( name => "foo" )
or warn $person_table->error;
isa_ok( $index1, 'SQL::Translator::Schema::Index', 'Index' );
is( $index1->name, 'foo', 'Index name is "foo"' );
is( $index1->is_valid, undef, 'Index name is not valid...' );
like( $index1->error, qr/no fields/i, '...because it has no fields' );
- is( join(':', $index1->fields('foo,bar')), 'foo:bar',
+ is( join(':', $index1->fields('foo,bar')), 'foo:bar',
'Index accepts fields');
is( $index1->is_valid, undef, 'Index name is not valid...' );
- like( $index1->error, qr/does not exist in table/i,
+ like( $index1->error, qr/does not exist in table/i,
'...because it used fields not in the table' );
- is( join(':', $index1->fields(qw[foo age])), 'foo:age',
+ is( join(':', $index1->fields(qw[foo age])), 'foo:age',
'Index accepts fields');
is( $index1->is_valid, 1, 'Index name is now valid' );
is( $index1->type, NORMAL, 'Index type is "normal"' );
- my $index2 = SQL::Translator::Schema::Index->new( name => "bar" )
+ my $index2 = SQL::Translator::Schema::Index->new( name => "bar" )
or warn SQL::Translator::Schema::Index->error;
$index2 = $person_table->add_index( $index2 );
isa_ok( $index2, 'SQL::Translator::Schema::Index', 'Index' );
#
my @constraints = $person_table->get_constraints;
is( scalar @constraints, 0, 'No constraints' );
- like( $person_table->error, qr/no constraints/i,
+ like( $person_table->error, qr/no constraints/i,
'Error for no constraints' );
- my $constraint1 = $person_table->add_constraint( name => 'foo' )
+ my $constraint1 = $person_table->add_constraint( name => 'foo' )
or warn $person_table->error;
isa_ok( $constraint1, 'SQL::Translator::Schema::Constraint', 'Constraint' );
is( $constraint1->name, 'foo', 'Constraint name is "foo"' );
is( $fields, 'age,name', 'Constraint field_names = "age,name"' );
is( $constraint1->match_type, '', 'Constraint match type is empty' );
- is( $constraint1->match_type('foo'), undef,
+ is( $constraint1->match_type('foo'), undef,
'Constraint match type rejects bad arg...' );
like( $constraint1->error, qr/invalid match type/i,
'...because it is invalid');
- is( $constraint1->match_type('FULL'), 'full',
+ is( $constraint1->match_type('FULL'), 'full',
'Constraint match type = "full"' );
my $constraint2 = SQL::Translator::Schema::Constraint->new( name => 'bar' );
) or die $person_table->error;
isa_ok( $constraint3, 'SQL::Translator::Schema::Constraint', 'Constraint' );
is( $constraint3->type, CHECK_C, 'Constraint type is "CHECK"' );
- is( $constraint3->expression, 'foo bar',
+ is( $constraint3->expression, 'foo bar',
'Constraint expression is "foo bar"' );
my $constraints = $person_table->get_constraints;
like( $schema->error, qr/no table/i, 'Error on no arg to get_table' );
$bad_table = $schema->get_table('baz');
- like( $schema->error, qr/does not exist/i,
+ like( $schema->error, qr/does not exist/i,
'Error on bad arg to get_table' );
my $bad_view = $schema->get_view;
like( $schema->error, qr/no view/i, 'Error on no arg to get_view' );
$bad_view = $schema->get_view('bar');
- like( $schema->error, qr/does not exist/i,
+ like( $schema->error, qr/does not exist/i,
'Error on bad arg to get_view' );
my $good_table = $schema->get_table('foo');
#
# Test ability to introspect some values
#
-{
- my $s = SQL::Translator::Schema->new(
+{
+ my $s = SQL::Translator::Schema->new(
name => 'foo',
database => 'PostgreSQL',
);
is( join('', $c->fields('foo')), 'foo', 'Fields now = "foo"' );
is( $c->is_valid, undef, 'Constraint on "person" not valid...');
- like( $c->error, qr/non-existent field/i,
+ like( $c->error, qr/non-existent field/i,
q[...because field "foo" doesn't exist] );
my $fk = $t->add_field( name => 'pet_id' );
$t->add_field( name => 'f2' );
is( join(',', $c->fields('f1,f2')), 'f1,f2', 'Fields now = "f1,f2"' );
is( $c->is_valid, undef, 'Constraint on "person" not valid...');
- like( $c->error, qr/only one field/i,
+ like( $c->error, qr/only one field/i,
q[...because too many fields for FK] );
$c->fields('f1');
is( $c->is_valid, undef, 'Constraint on "person" not valid...');
- like( $c->error, qr/no reference table/i,
+ like( $c->error, qr/no reference table/i,
q[...because there's no reference table] );
is( $c->reference_table('foo'), 'foo', 'Reference table now = "foo"' );
is( $c->is_valid, undef, 'Constraint on "person" not valid...');
- like( $c->error, qr/no table named/i,
+ like( $c->error, qr/no table named/i,
q[...because reference table "foo" doesn't exist] );
my $t2 = $s->add_table( name => 'pet' );
like( $c->error, qr/no reference fields/i,
q[...because there're no reference fields]);
- is( join('', $c->reference_fields('pet_id')), 'pet_id',
+ is( join('', $c->reference_fields('pet_id')), 'pet_id',
'Reference fields = "pet_id"' );
is( $c->is_valid, undef, 'Constraint on "person" not valid...');
my $pet_id = $t2->add_field( name => 'pet_id' );
is( $pet_id->name, 'pet_id', 'Added field "pet_id"' );
-
+
is( $c->is_valid, 1, 'Constraint now valid' );
}
is( $t->primary_key, undef, 'No primary key' );
- is( $t->primary_key('person_id'), undef,
+ is( $t->primary_key('person_id'), undef,
q[Can't make PK on "person_id"...] );
like( $t->error, qr/invalid field/i, "...because it doesn't exist" );
$t->add_field( name => 'name' );
$c = $t->primary_key('name');
- is( join(',', $c->fields), 'person_id,name',
+ is( join(',', $c->fields), 'person_id,name',
'Constraint now on "person_id" and "name"' );
is( scalar @{ $t->get_constraints }, 1, 'Found 1 constraint' );
isa_ok( $t->schema, 'SQL::Translator::Schema', 'Schema' );
is( $t->schema->name, 'TrigTest', qq[Schema name is "'TrigTest'"] );
is( $t->name, $name, qq[Name is "$name"] );
- is( $t->perform_action_when, $perform_action_when,
+ is( $t->perform_action_when, $perform_action_when,
qq[Perform action when is "$perform_action_when"] );
- is( join(',', $t->database_events), $database_events,
+ is( join(',', $t->database_events), $database_events,
qq[Database event is "$database_events"] );
isa_ok( $t->table, 'SQL::Translator::Schema::Table', qq[table is a Table"] );
is( $t->action, $action, qq[Action is "$action"] );
- my $s2 = SQL::Translator::Schema->new(name => 'TrigTest2');
+ my $s2 = SQL::Translator::Schema->new(name => 'TrigTest2');
$s2->add_table(name=>'foo') or die "Couldn't create table: ", $s2->error;
my $t2 = $s2->add_trigger(
name => 'foo_trigger',
on_table => 'foo',
action => 'update modified=timestamp();',
) or die $s2->error;
- isa_ok( $t2, 'SQL::Translator::Schema::Trigger', 'Trigger' );
+ isa_ok( $t2, 'SQL::Translator::Schema::Trigger', 'Trigger' );
isa_ok( $t2->schema, 'SQL::Translator::Schema', 'Schema' );
is( $t2->schema->name, 'TrigTest2', qq[Schema name is "'TrigTest2'"] );
is( $t2->name, 'foo_trigger', qq[Name is "foo_trigger"] );
- is_deeply(
+ is_deeply(
[$t2->database_events],
[qw/insert update/],
"Database events are [qw/insert update/] "
);
- isa_ok($t2->database_events,'ARRAY','Database events');
-
- #
- # Trigger equal tests
- #
- isnt(
+ isa_ok($t2->database_events,'ARRAY','Database events');
+
+ #
+ # Trigger equal tests
+ #
+ isnt(
$t1->equals($t2),
1,
'Compare two Triggers with database_event and database_events'
);
- $t1->database_events($database_events);
- $t2->database_events($database_events);
- is($t1->equals($t2),1,'Compare two Triggers with database_event');
+ $t1->database_events($database_events);
+ $t2->database_events($database_events);
+ is($t1->equals($t2),1,'Compare two Triggers with database_event');
+
+ $t2->database_events('');
+ $t1->database_events([qw/update insert/]);
+ $t2->database_events([qw/insert update/]);
+ is($t1->equals($t2),1,'Compare two Triggers with database_events');
- $t2->database_events('');
- $t1->database_events([qw/update insert/]);
- $t2->database_events([qw/insert update/]);
- is($t1->equals($t2),1,'Compare two Triggers with database_events');
-
#
# $schema-> drop_trigger
#
$s->add_trigger($t);
}
-
+
#
# Procedure
#
alter table t_test1 alter column f_char drop default;
- -- The following are allowed by the grammar
+ -- The following are allowed by the grammar
-- but won\'t do anything... - ky
alter table t_text1 alter column f_char set not null;
my $sql = q[
CREATE TABLE qtl_trait_category
(
- qtl_trait_category_id NUMBER(11) NOT NULL
+ qtl_trait_category_id NUMBER(11) NOT NULL
CONSTRAINT pk_qtl_trait_category PRIMARY KEY,
trait_category VARCHAR2(100) NOT NULL,
- CONSTRAINT AVCON_4287_PARAM_000 CHECK
+ CONSTRAINT AVCON_4287_PARAM_000 CHECK
(trait_category IN ('S', 'A', 'E')) ENABLE,
UNIQUE ( trait_category )
);
- COMMENT ON TABLE qtl_trait_category IS
+ COMMENT ON TABLE qtl_trait_category IS
'hey, hey, hey, hey';
- comment on column qtl_trait_category.qtl_trait_category_id
+ comment on column qtl_trait_category.qtl_trait_category_id
is 'the primary key!';
-- foo bar comment
CREATE TABLE qtl_trait
(
- qtl_trait_id NUMBER(11) NOT NULL
+ qtl_trait_id NUMBER(11) NOT NULL
CONSTRAINT pk_qtl_trait PRIMARY KEY,
trait_symbol VARCHAR2(100 BYTE) NOT NULL,
trait_name VARCHAR2(200 CHAR) NOT NULL,
CREATE TABLE qtl
(
/* qtl_id comment */
- qtl_id NUMBER(11) NOT NULL
+ qtl_id NUMBER(11) NOT NULL
CONSTRAINT pk_qtl PRIMARY KEY,
qtl_accession_id VARCHAR2(20) NOT NULL /* accession comment */,
published_symbol VARCHAR2(100),
CREATE TABLE qtl_trait_synonym
(
- qtl_trait_synonym_id NUMBER(11) NOT NULL
+ qtl_trait_synonym_id NUMBER(11) NOT NULL
CONSTRAINT pk_qtl_trait_synonym PRIMARY KEY,
trait_synonym VARCHAR2(200) NOT NULL,
qtl_trait_id NUMBER(11) NOT NULL,
);
-- View and procedure testing
- CREATE OR REPLACE PROCEDURE CMDOMAIN_LATEST.P_24_HOUR_EVENT_SUMMARY
- IS
- ldate varchar2(10);
- user_added INT;
- user_deleted INT;
- workingsets_created INT;
- change_executed INT;
- change_detected INT;
- reports_run INT;
- backup_complete INT;
- backup_failed INT;
- devices_in_inventory INT;
-
-
- BEGIN
-
- select CAST(TO_CHAR(sysdate,'MM/DD/YYYY') AS varchar2(10)) INTO ldate from dual;
- END;
+ CREATE OR REPLACE PROCEDURE CMDOMAIN_LATEST.P_24_HOUR_EVENT_SUMMARY
+ IS
+ ldate varchar2(10);
+ user_added INT;
+ user_deleted INT;
+ workingsets_created INT;
+ change_executed INT;
+ change_detected INT;
+ reports_run INT;
+ backup_complete INT;
+ backup_failed INT;
+ devices_in_inventory INT;
+
+ BEGIN
+ select CAST(TO_CHAR(sysdate,'MM/DD/YYYY') AS varchar2(10)) INTO ldate from dual;
+ END;
/
-
- CREATE OR REPLACE FORCE VIEW CMDOMAIN_MIG.VS_ASSET (ASSET_ID, FQ_NAME, FOLDER_NAME, ASSET_NAME, ANNOTATION, ASSET_TYPE, FOREIGN_ASSET_ID, FOREIGN_ASSET_ID2, DATE_CREATED, DATE_MODIFIED, CONTAINER_ID, CREATOR_ID, MODIFIER_ID, USER_ACCESS) AS
- SELECT
- a.asset_id, a.fq_name,
- ap_extract_folder(a.fq_name) AS folder_name,
- ap_extract_asset(a.fq_name) AS asset_name,
- a.annotation,
- a.asset_type,
- a.foreign_asset_id,
- a.foreign_asset_id2,
- a.dateCreated AS date_created,
- a.dateModified AS date_modified,
- a.container_id,
- a.creator_id,
- a.modifier_id,
- m.user_id AS user_access
- from asset a
- JOIN M_ACCESS_CONTROL m on a.acl_id = m.acl_id;
+
+ CREATE OR REPLACE FORCE VIEW CMDOMAIN_MIG.VS_ASSET (ASSET_ID, FQ_NAME, FOLDER_NAME, ASSET_NAME, ANNOTATION, ASSET_TYPE, FOREIGN_ASSET_ID, FOREIGN_ASSET_ID2, DATE_CREATED, DATE_MODIFIED, CONTAINER_ID, CREATOR_ID, MODIFIER_ID, USER_ACCESS) AS
+ SELECT
+ a.asset_id, a.fq_name,
+ ap_extract_folder(a.fq_name) AS folder_name,
+ ap_extract_asset(a.fq_name) AS asset_name,
+ a.annotation,
+ a.asset_type,
+ a.foreign_asset_id,
+ a.foreign_asset_id2,
+ a.dateCreated AS date_created,
+ a.dateModified AS date_modified,
+ a.container_id,
+ a.creator_id,
+ a.modifier_id,
+ m.user_id AS user_access
+ from asset a
+ JOIN M_ACCESS_CONTROL m on a.acl_id = m.acl_id;
];
is( scalar @t1_fields, 2, '2 fields in table' );
my $f1 = shift @t1_fields;
-is( $f1->name, 'qtl_trait_category_id',
+is( $f1->name, 'qtl_trait_category_id',
'First field is "qtl_trait_category_id"' );
is( $f1->data_type, 'number', 'Field is a number' );
is( $f1->size, 11, 'Size is "11"' );
is( scalar @t1_constraints, 3, '3 constraints on table' );
my $c1 = $t1_constraints[0];
-is( $c1->name, 'pk_qtl_trait_category',
+is( $c1->name, 'pk_qtl_trait_category',
'Constraint name is "pk_qtl_trait_category"' );
is( $c1->type, PRIMARY_KEY, 'First constraint is PK' );
-is( join(',', $c1->fields), 'qtl_trait_category_id',
+is( join(',', $c1->fields), 'qtl_trait_category_id',
'Constraint is on field "qtl_trait_category_id"' );
my $c2 = $t1_constraints[1];
is( $c2->type, CHECK_C, 'Second constraint is a check' );
-is( $c2->expression,
+is( $c2->expression,
"( trait_category IN ('S', 'A', 'E') ) ENABLE",
'Constraint is on field "trait_category"' );
my $c3 = $t1_constraints[2];
is( $c3->type, UNIQUE, 'Third constraint is unique' );
-is( join(',', $c3->fields), 'trait_category',
+is( join(',', $c3->fields), 'trait_category',
'Constraint is on field "trait_category"' );
#
is( $t2_f3->is_foreign_key, 0, 'Field is not a FK' );
my $t2_f4 = shift @t2_fields;
-is( $t2_f4->name, 'qtl_trait_category_id',
+is( $t2_f4->name, 'qtl_trait_category_id',
'Fourth field is "qtl_trait_category_id"' );
is( $t2_f4->data_type, 'number', 'Field is a number' );
is( $t2_f4->size, 11, 'Size is "11"' );
is( $t2_f4->is_foreign_key, 1, 'Field is a FK' );
my $f4_fk = $t2_f4->foreign_key_reference;
isa_ok( $f4_fk, 'SQL::Translator::Schema::Constraint', 'FK' );
-is( $f4_fk->reference_table, 'qtl_trait_category',
+is( $f4_fk->reference_table, 'qtl_trait_category',
'FK references table "qtl_trait_category"' );
-is( join(',', $f4_fk->reference_fields), 'qtl_trait_category_id',
+is( join(',', $f4_fk->reference_fields), 'qtl_trait_category_id',
'FK references field "qtl_trait_category_id"' );
my @t2_constraints = $t2->get_constraints;
my $t2_c4 = shift @t2_constraints;
is( $t2_c4->type, FOREIGN_KEY, 'Fourth constraint is FK' );
is( $t2_c4->name, '', 'No name' );
-is( join(',', $t2_c4->fields), 'qtl_trait_category_id',
+is( join(',', $t2_c4->fields), 'qtl_trait_category_id',
'Fields = "qtl_trait_category_id"' );
-is( $t2_c4->reference_table, 'qtl_trait_category',
+is( $t2_c4->reference_table, 'qtl_trait_category',
'Reference table = "qtl_trait_category"' );
-is( join(',', $t2_c4->reference_fields), 'qtl_trait_category_id',
+is( join(',', $t2_c4->reference_fields), 'qtl_trait_category_id',
'Reference fields = "qtl_trait_category_id"' );
is( $t3_f1->comments, 'qtl_id comment', 'Comment "qtl_id comment" exists' );
my $t3_f2 = shift @t3_fields;
-is( $t3_f2->comments, 'accession comment',
+is( $t3_f2->comments, 'accession comment',
'Comment "accession comment" exists' );
my @t3_indices = $t3->get_indices;
my $t4_c3 = $t4_constraints[2];
is( $t4_c3->type, FOREIGN_KEY, 'Third constraint is FK' );
is( $t4_c3->name, '', 'No name' );
-is( join(',', $t4_c3->fields), 'qtl_trait_id',
+is( join(',', $t4_c3->fields), 'qtl_trait_id',
'Fields = "qtl_trait_id"' );
-is( $t4_c3->reference_table, 'qtl_trait',
+is( $t4_c3->reference_table, 'qtl_trait',
'Reference table = "qtl_trait"' );
-is( join(',', $t4_c3->reference_fields), 'qtl_trait_id',
+is( join(',', $t4_c3->reference_fields), 'qtl_trait_id',
'Reference fields = "qtl_trait_id"' );
-is( $t4_c3->on_delete, 'SET NULL',
+is( $t4_c3->on_delete, 'SET NULL',
'on_delete = "SET NULL"' );
my @views = $schema->get_views;
is( $view1->name, 'VS_ASSET', 'Found "VS_ASSET" view' );
like($view1->sql, qr/VS_ASSET/, "Detected view VS_ASSET");
unlike($view1->sql, qr/CMDOMAIN_MIG/, "Did not detect CMDOMAIN_MIG");
-
+
my @procs = $schema->get_procedures;
is( scalar @procs, 1, 'Right number of procedures (1)' );
my $proc1 = shift @procs;
-#!/usr/bin/perl -w
+#!/usr/bin/perl -w
# vim:filetype=perl
# Before `make install' is performed this script should be runnable with
ok("$xml" ne "" ,"Produced something!");
print "XML attrib_values=>1:\n$xml" if DEBUG;
# Strip sqlf header with its variable date so we diff safely
- $xml =~ s/^([^\n]*\n){7}//m;
+ $xml =~ s/^([^\n]*\n){7}//m;
eq_or_diff $xml, $ans ,"XML looks right";
} # end View
ok("$xml" ne "" ,"Produced something!");
print "XML attrib_values=>1:\n$xml" if DEBUG;
# Strip sqlf header with its variable date so we diff safely
- $xml =~ s/^([^\n]*\n){7}//m;
+ $xml =~ s/^([^\n]*\n){7}//m;
eq_or_diff $xml, $ans ,"XML looks right";
} # end Trigger
ok("$xml" ne "" ,"Produced something!");
print "XML attrib_values=>1:\n$xml" if DEBUG;
# Strip sqlf header with its variable date so we diff safely
- $xml =~ s/^([^\n]*\n){7}//m;
+ $xml =~ s/^([^\n]*\n){7}//m;
eq_or_diff $xml, $ans ,"XML looks right";
} # end Procedure
-#!/usr/bin/perl -w
+#!/usr/bin/perl -w
# vim:filetype=perl
# Before `make install' is performed this script should be runnable with
my $out;
lives_ok { $out = $obj->translate; } "Translate ran";
ok $out ne "" ,"Produced something!";
- local $/ = undef; # slurp
- eq_or_diff $out, <DATA> ,"Output looks right";
+ eq_or_diff
+ $out,
+ do { local (@ARGV, $/) = "$Bin/data/template/testresult_basic.txt"; <> },
+ "Output looks right"
+ ;
}
# Test passing of Template config
Table: Another}
,"Output looks right";
}
-
-
-__DATA__
-Schema:
-Database:
-
-Foo: bar
-Hello: world
-
-Table: Basic
-==========================================================================
-
-Fields
- id
- data_type: int
- size: 10
- is_nullable: 0
- default_value:
- is_primary_key: 1
- is_unique: 0
- is_auto_increment: 1
- is_foreign_key: 0
- foreign_key_reference:
- is_valid: 1
- order: 1
- table: Basic
-
- title
- data_type: varchar
- size: 100
- is_nullable: 0
- default_value: hello
- is_primary_key: 0
- is_unique: 1
- is_auto_increment: 0
- is_foreign_key: 0
- foreign_key_reference:
- is_valid: 1
- order: 2
- table: Basic
-
- description
- data_type: text
- size: 0
- is_nullable: 1
- default_value:
- is_primary_key: 0
- is_unique: 0
- is_auto_increment: 0
- is_foreign_key: 0
- foreign_key_reference:
- is_valid: 1
- order: 3
- table: Basic
-
- email
- data_type: varchar
- size: 500
- is_nullable: 1
- default_value:
- is_primary_key: 0
- is_unique: 1
- is_auto_increment: 0
- is_foreign_key: 0
- foreign_key_reference:
- is_valid: 1
- order: 4
- table: Basic
-
- explicitnulldef
- data_type: varchar
- size: 0
- is_nullable: 1
- default_value:
- is_primary_key: 0
- is_unique: 0
- is_auto_increment: 0
- is_foreign_key: 0
- foreign_key_reference:
- is_valid: 1
- order: 5
- table: Basic
-
- explicitemptystring
- data_type: varchar
- size: 0
- is_nullable: 1
- default_value:
- is_primary_key: 0
- is_unique: 0
- is_auto_increment: 0
- is_foreign_key: 0
- foreign_key_reference:
- is_valid: 1
- order: 6
- table: Basic
-
- emptytagdef
- data_type: varchar
- size: 0
- is_nullable: 1
- default_value:
- is_primary_key: 0
- is_unique: 0
- is_auto_increment: 0
- is_foreign_key: 0
- foreign_key_reference:
- is_valid: 1
- order: 7
- table: Basic
-
- another_id
- data_type: int
- size: 10
- is_nullable: 1
- default_value: 2
- is_primary_key: 0
- is_unique: 0
- is_auto_increment: 0
- is_foreign_key: 1
- foreign_key_reference: Another
- is_valid: 1
- order: 8
- table: Basic
-
- timest
- data_type: timestamp
- size: 0
- is_nullable: 1
- default_value:
- is_primary_key: 0
- is_unique: 0
- is_auto_increment: 0
- is_foreign_key: 0
- foreign_key_reference:
- is_valid: 1
- order: 9
- table: Basic
-
-
-Indices
- titleindex
- table: Basic
- fields: title
- type: NORMAL
- options:
- is_valid: 1
-
-
-Constraints
- ?
- type: PRIMARY KEY
- fields: id
- expression:
- match_type:
- reference_fields:
- reference_table:
- deferrable: 1
- on_delete:
- on_update:
- options:
- is_valid: 1
-
- emailuniqueindex
- type: UNIQUE
- fields: email
- expression:
- match_type:
- reference_fields:
- reference_table:
- deferrable: 1
- on_delete:
- on_update:
- options:
- is_valid: 1
-
- very_long_index_name_on_title_field_which_should_be_truncated_for_various_rdbms
- type: UNIQUE
- fields: title
- expression:
- match_type:
- reference_fields:
- reference_table:
- deferrable: 1
- on_delete:
- on_update:
- options:
- is_valid: 1
-
- ?
- type: FOREIGN KEY
- fields: another_id
- expression:
- match_type:
- reference_fields: id
- reference_table: Another
- deferrable: 1
- on_delete:
- on_update:
- options:
- is_valid: 1
-
-Table: Another
-==========================================================================
-
-Fields
- id
- data_type: int
- size: 10
- is_nullable: 0
- default_value:
- is_primary_key: 1
- is_unique: 0
- is_auto_increment: 1
- is_foreign_key: 0
- foreign_key_reference:
- is_valid: 1
- order: 1
- table: Another
-
- num
- data_type: numeric
- size: 10,2
- is_nullable: 1
- default_value:
- is_primary_key: 0
- is_unique: 0
- is_auto_increment: 0
- is_foreign_key: 0
- foreign_key_reference:
- is_valid: 1
- order: 2
- table: Another
-
-
-Indices
-
-Constraints
- ?
- type: PRIMARY KEY
- fields: id
- expression:
- match_type:
- reference_fields:
- reference_table:
- deferrable: 1
- on_delete:
- on_update:
- options:
- is_valid: 1
-
is( scalar @constraints, 1, 'One constraint' );
is( $constraints[0]->type, UNIQUE, 'Constraint is UNIQUE' );
- is( join(',', $constraints[0]->fields),
+ is( join(',', $constraints[0]->fields),
'mdinfo,mdaver_end,srvver_end', 'On "mdinfo,mdaver_end,srvver_end"' );
}
BEGIN {
maybe_plan(3,
'SQL::Translator::Parser::DBI::Sybase',
- );
+ );
}
use_ok('SQL::Translator::Parser::DBI::Sybase');
my $c1 = pop @constraints;
is( $c1->type, 'FOREIGN KEY', 'FK constraint' );
is( $c1->reference_table, 'person', 'References person table' );
- is( join(',', $c1->reference_fields), 'person_id',
+ is( join(',', $c1->reference_fields), 'person_id',
'References person_id field' );
my @views = $schema->get_views;
is( $c1->type, 'FOREIGN KEY', 'FK constraint' );
is( $c1->reference_table, 'person', 'References person table' );
is( $c1->name, 'fk_person_id', 'Constraint name fk_person_id' );
- is( join(',', $c1->reference_fields), 'person_id',
+ is( join(',', $c1->reference_fields), 'person_id',
'References person_id field' );
}
my ($p, $tables, $classes);
$p = HTML::Parser->new(api_version => 3);
-$p->strict_names(1);
+$p->strict_names(1);
my $create = q|
CREATE TABLE foo (
my $status;
eval {
- $status = $p->parse($parsed);
+ $status = $p->parse($parsed);
};
if ($@) {
daig $@;
$classes++;
}
}, 'tagname,attr',
- ],
+ ],
);
}
);
}
-ok(-e $sqlt_diff, 'Found sqlt-diff script');
+ok(-e $sqlt_diff, 'Found sqlt-diff script');
my @cmd = ($^X, $sqlt_diff, "$create1=SQLite", "$create2=SQLite");
my $out = `@cmd`;
like($out, qr/-- Target database SQLite is untested/, "Detected 'untested' comment");
like($out, qr/ALTER TABLE person CHANGE iq/, "Detected altered 'iq' field");
-like($out, qr/ALTER TABLE person ADD is_rock_star/,
+like($out, qr/ALTER TABLE person ADD is_rock_star/,
"Detected missing rock star field");
-
+
@cmd = ($^X, $sqlt_diff, "$create1=SQLite", "$create1=SQLite");
$out = `@cmd`;
like($out, qr/ALTER TABLE person CHANGE iq/, "Detected altered 'iq' field");
like($out, qr/ALTER TABLE person CHANGE name/, "Detected altered 'name' field");
like($out, qr/ALTER TABLE person CHANGE age/, "Detected altered 'age' field");
-like($out, qr/ALTER TABLE person ADD is_rock_star/,
+like($out, qr/ALTER TABLE person ADD is_rock_star/,
"Detected missing rock star field");
-like($out, qr/ALTER TABLE person ADD UNIQUE UC_person_id/,
+like($out, qr/ALTER TABLE person ADD UNIQUE UC_person_id/,
"Detected missing unique constraint");
-like($out, qr/CREATE UNIQUE INDEX unique_name/,
+like($out, qr/CREATE UNIQUE INDEX unique_name/,
"Detected unique index with different name");
-like($out, qr/ALTER TABLE person ENGINE=InnoDB;/,
+like($out, qr/ALTER TABLE person ENGINE=InnoDB;/,
"Detected altered table option");
-like($out, qr/ALTER TABLE employee DROP FOREIGN KEY FK5302D47D93FE702E/,
+like($out, qr/ALTER TABLE employee DROP FOREIGN KEY FK5302D47D93FE702E/,
"Detected drop foreign key");
-like($out, qr/ALTER TABLE employee ADD CONSTRAINT FK5302D47D93FE702E_diff/,
+like($out, qr/ALTER TABLE employee ADD CONSTRAINT FK5302D47D93FE702E_diff/,
"Detected add constraint");
unlike($out, qr/ALTER TABLE employee ADD PRIMARY KEY/, "Primary key looks different when it shouldn't");
$out = `@cmd`;
unlike($out, qr/-- Target database Oracle is untested/, "Did not detect 'untested' comment");
-like($out, qr/ALTER TABLE TABLE1 DROP FOREIGN KEY/,
+like($out, qr/ALTER TABLE TABLE1 DROP FOREIGN KEY/,
"Detected drop foreign key");
-like($out, qr/ALTER TABLE TABLE1 ADD CONSTRAINT/,
+like($out, qr/ALTER TABLE TABLE1 ADD CONSTRAINT/,
"Detected add constraint");
or die $tr->error;
my $out = $t->translate( catfile($Bin, qw/data diff/, $_ ) )
or die $tr->error;
-
+
my $schema = $t->schema;
unless ( $schema->name ) {
$schema->name( $_ );
} (qw( create1.yml create2.yml ));
# Test for differences
-my @out = SQL::Translator::Diff::schema_diff(
- $source_schema, 'MySQL',
+my @out = SQL::Translator::Diff::schema_diff(
+ $source_schema, 'MySQL',
$target_schema, 'MySQL',
- {
- no_batch_alters => 1,
- producer_args => { quote_table_names => 0 }
- }
+ {
+ no_batch_alters => 1,
+ producer_args => { quote_table_names => 0 }
+ }
);
ok( @out, 'Got a list' );
# Lets remove the renamed table so we dont have to change the SQL or other tests
$target_schema->drop_table('new_name');
-
+
my $schema = $t->schema;
unless ( $schema->name ) {
$schema->name( 'create.sql' );
}
- # Now lets change the type of one of the 'integer' columns so that it
+ # Now lets change the type of one of the 'integer' columns so that it
# matches what the mysql parser sees for '<col> interger'.
my $field = $target_schema->get_table('employee')->get_field('employee_id');
$field->data_type('integer');
}
{
- # Test other things about renaming tables to - namely that renames
+ # Test other things about renaming tables to - namely that renames
# constraints are still formated right.
my $s1 = SQL::Translator::Schema->new;
## END OF DIFF
# Test quoting works too.
- $out = SQL::Translator::Diff::schema_diff($s1, 'MySQL', $s2, 'MySQL',
+ $out = SQL::Translator::Diff::schema_diff($s1, 'MySQL', $s2, 'MySQL',
{ producer_args => { quote_table_names => '`' } }
);
eq_or_diff($out, <<'## END OF DIFF', "Quoting can be turned on");
or die $tr->error;
my $out = $t->translate( catfile($Bin, qw/data diff pgsql/, $_ ) )
or die $tr->error;
-
+
my $schema = $t->schema;
unless ( $schema->name ) {
$schema->name( $_ );
or die $tr->error;
my $out = $t->translate( catfile($Bin, qw/data diff/, $_ ) )
or die $tr->error;
-
+
my $schema = $t->schema;
unless ( $schema->name ) {
$schema->name( $_ );
} (qw/create1.yml create2.yml/);
# Test for differences
-my $out = SQL::Translator::Diff::schema_diff( $source_schema, 'SQLite', $target_schema, 'SQLite',
- { no_batch_alters => 1,
+my $out = SQL::Translator::Diff::schema_diff( $source_schema, 'SQLite', $target_schema, 'SQLite',
+ { no_batch_alters => 1,
ignore_missing_methods => 1,
output_db => 'SQLite',
- }
+ }
);
eq_or_diff($out, <<'## END OF DIFF', "Diff as expected");
or die $tr->error;
my $out = $t->translate( catfile($Bin, qw/data diff /, $_ ) )
or die $tr->error;
-
+
my $schema = $t->schema;
unless ( $schema->name ) {
$schema->name( $_ );
my $diff_hash = make_diff_hash();
eq_or_diff($diff_hash->{employee},
- {
+ {
constraints_to_create => [ 'FK5302D47D93FE702E_diff' ],
constraints_to_drop => [ 'FK5302D47D93FE702E' ],
fields_to_drop => [ 'job_title' ]
{
constraints_to_create => [ 'UC_person_id', 'UC_age_name' ],
constraints_to_drop => [ 'UC_age_name' ],
- fields_to_alter => [
+ fields_to_alter => [
'person_id person_id',
'name name',
'age age',
$diff_hash = make_diff_hash();
eq_or_diff($diff_hash->{employee},
- {
+ {
fields_to_drop => [ 'job_title' ]
},
"Correct differences correct on employee table");
{
constraints_to_create => [ 'UC_person_id', 'UC_age_name' ],
constraints_to_drop => [ 'UC_age_name' ],
- fields_to_alter => [
+ fields_to_alter => [
'person_id person_id',
'name name',
'age age',
my %table_diffs = (
map {
-
+
my $opt = $table_diff->{$_};
@$opt ? ( $_ => [ map {
(ref $_||'') eq 'ARRAY' ? "@$_" :
(ref $_) ? $_->name
: "$_";
- } @$opt
- ] )
+ } @$opt
+ ] )
: ()
} keys %$table_diff
);
BEGIN {
maybe_plan(
- 5,
+ 5,
'DBI',
'SQL::Translator::Parser::SQLite',
'SQL::Translator::Producer::Dumper'
-#!/usr/bin/perl -w
+#!/usr/bin/perl -w
# vim:filetype=perl
# Before `make install' is performed this script should be runnable with
# Normal output looks ok
local $/ = undef; # slurp
-eq_or_diff $out, <DATA> ,"Output looks right";
+eq_or_diff
+ $out,
+ do { local (@ARGV, $/) = "$Bin/data/template/testresult_table.txt"; <> },
+ "Output looks right"
+;
# File output
my @files = glob("$tdir/*.txt");
open(FILE, "$tdir/person.txt") || die "Couldn't open $tdir/person.txt : $!";
eq_or_diff <FILE>, qq{Table: person
Primary Key: person_id
- Foreign Keys:
+ Foreign Keys:\x20
Data Fields: name, age, weight, iq, description
}
open(FILE, "$tdir/pet.txt") || die "Couldn't open $tdir/pet.txt : $!";
eq_or_diff <FILE>, qq{Table: pet
Primary Key: pet_id, person_id
- Foreign Keys:
+ Foreign Keys:\x20
Data Fields: name, age
}
, "pet.txt looks right";
close(FILE);
-
print $out if DEBUG;
#print "Debug:", Dumper($obj) if DEBUG;
-
-__DATA__
-Table: person
- Primary Key: person_id
- Foreign Keys:
- Data Fields: name, age, weight, iq, description
-
-Table: pet
- Primary Key: pet_id, person_id
- Foreign Keys:
- Data Fields: name, age
-
data => $in_yaml,
filters => [
# Filter from SQL::Translator::Filter::*
- [ 'Names', {
+ [ 'Names', {
tables => 'lc',
fields => 'ucfirst',
} ],
lives_ok { $out = $obj->translate; } "Translate ran";
is $obj->error, '' ,"No errors";
ok $out ne "" ,"Produced something!";
-# Somewhat hackishly modify the yaml with a regex to avoid
+# Somewhat hackishly modify the yaml with a regex to avoid
# failing randomly on every change of version.
$out =~ s/version: .*/version: SUPPRESSED/;
eq_or_diff $out, $ans_yaml ,"Output looks right";
thing:
name: thing
extra:
- mysql_charset: latin1
- mysql_collate: latin1_danish_ci
+ mysql_charset: latin1
+ mysql_collate: latin1_danish_ci
order: 1
fields:
id:
};
for my $size (keys %$number_sizes) {
my $expected = $number_sizes->{$size};
- my $number_field = SQL::Translator::Schema::Field->new(
+ my $number_field = SQL::Translator::Schema::Field->new(
name => "numberfield_$expected",
table => $table,
data_type => 'number',
size => $size,
is_nullable => 1,
is_foreign_key => 0,
- is_unique => 0
+ is_unique => 0
);
is(
my $varchars;
for my $size (qw/255 256 65535 65536/) {
- $varchars->{$size} = SQL::Translator::Schema::Field->new(
+ $varchars->{$size} = SQL::Translator::Schema::Field->new(
name => "vch_$size",
table => $table,
data_type => 'varchar',
is (
SQL::Translator::Producer::MySQL::create_field($varchars->{255}, { mysql_version => 5.000003 }),
- 'vch_255 varchar(255)',
+ 'vch_255 varchar(255)',
'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)',
'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)',
'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)',
'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',
'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',
'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)',
'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',
'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',
'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',
'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',
'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',
'VARCHAR(65536) is substituted with TEXT when no version specified',
);
quote_field_names => $qf,
};
-
+
my $alter_field = SQL::Translator::Producer::MySQL::alter_field($field1, $field2, $options);
is($alter_field, 'ALTER TABLE `mydb`.`mytable` CHANGE COLUMN `myfield` `myfield` VARCHAR(25) NOT NULL', 'Alter field works');
};
for my $size (keys %$number_sizes) {
my $expected = $number_sizes->{$size};
- my $number_field = SQL::Translator::Schema::Field->new(
+ my $number_field = SQL::Translator::Schema::Field->new(
name => "numberfield_$expected",
table => $table,
data_type => 'number',
size => $size,
is_nullable => 1,
is_foreign_key => 0,
- is_unique => 0
+ is_unique => 0
);
is(
my $varchars;
for my $size (qw/255 256 65535 65536/) {
- $varchars->{$size} = SQL::Translator::Schema::Field->new(
+ $varchars->{$size} = SQL::Translator::Schema::Field->new(
name => "vch_$size",
table => $table,
data_type => 'varchar',
is (
SQL::Translator::Producer::MySQL::create_field($varchars->{255}, { mysql_version => 5.000003, %$options }),
- '`vch_255` varchar(255)',
+ '`vch_255` varchar(255)',
'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)',
'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)',
'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)',
'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',
'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',
'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)',
'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',
'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',
'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',
'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',
'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',
'VARCHAR(65536) is substituted with TEXT when no version specified',
);
BEGIN {
maybe_plan(1,
'SQL::Translator::Parser::DBI::Oracle',
- );
+ );
}
use_ok('SQL::Translator::Parser::DBI::Oracle');
size => 7,
);
-my $field3_datetime_with_TZ_sql =
+my $field3_datetime_with_TZ_sql =
SQL::Translator::Producer::PostgreSQL::create_field(
$field3_datetime_with_TZ
);
is(
- $field3_datetime_with_TZ_sql,
- 'datetime_with_TZ timestamp(6) with time zone',
+ $field3_datetime_with_TZ_sql,
+ 'datetime_with_TZ timestamp(6) with time zone',
'Create time field with time zone and size, works'
);
size => 2,
);
-my $field3_time_without_TZ_sql
+my $field3_time_without_TZ_sql
= SQL::Translator::Producer::PostgreSQL::create_field(
$field3_time_without_TZ
);
is(
- $field3_time_without_TZ_sql,
- 'time_without_TZ time(2) without time zone',
+ $field3_time_without_TZ_sql,
+ 'time_without_TZ time(2) without time zone',
'Create time field without time zone but with size, works'
);
CREATE VIEW view_foo ( id, name ) AS
SELECT id, name FROM thing
";
-
+
is($drop_view_8_1_produced, $drop_view_8_1_expected, "My DROP VIEW statement for 8.1 is correct");
my $drop_view_opts2 = { add_drop_view => 1, no_comments => 1, postgres_version => 9.001 };
CREATE VIEW view_foo ( id, name ) AS
SELECT id, name FROM thing
";
-
+
is($drop_view_9_1_produced, $drop_view_9_1_expected, "My DROP VIEW statement for 9.1 is correct");
filename => $xmlfile,
) or die $sqlt->error;
-eq_or_diff(\@sql,
+eq_or_diff(\@sql,
[
'BEGIN TRANSACTION',
q<DROP TABLE 'Basic'>,
is( scalar @constraints, 1, 'One constraint' );
is( $constraints[0]->type, UNIQUE, 'Constraint is UNIQUE' );
- is( join(',', $constraints[0]->fields),
+ is( join(',', $constraints[0]->fields),
'mdinfo,mdaver_end,srvver_end', 'On "mdinfo,mdaver_end,srvver_end"' );
}
filename => $xmlfile,
) or die $sqlt->error;
-my $want = [
+my $want = [
'DROP TABLE Basic CASCADE CONSTRAINTS',
'DROP SEQUENCE sq_Basic_id',
'CREATE SEQUENCE sq_Basic_id',
'CREATE OR REPLACE TRIGGER ts_Basic_timest
BEFORE INSERT OR UPDATE ON Basic
FOR EACH ROW WHEN (new.timest IS NULL)
-BEGIN
+BEGIN
SELECT sysdate INTO :new.timest FROM dual;
END;
',
CREATE OR REPLACE TRIGGER ts_Basic_timest01
BEFORE INSERT OR UPDATE ON Basic
FOR EACH ROW WHEN (new.timest IS NULL)
-BEGIN
+BEGIN
SELECT sysdate INTO :new.timest FROM dual;
END;
/
filename => $xmlfile,
) or die $sqlt->error;
-my $want = [
+my $want = [
'DROP TABLE "Basic" CASCADE CONSTRAINTS',
'DROP SEQUENCE "sq_Basic_id"',
'CREATE SEQUENCE "sq_Basic_id"',
'CREATE OR REPLACE TRIGGER "ts_Basic_timest"
BEFORE INSERT OR UPDATE ON "Basic"
FOR EACH ROW WHEN (new."timest" IS NULL)
-BEGIN
+BEGIN
SELECT sysdate INTO :new."timest" FROM dual;
END;
',
CREATE OR REPLACE TRIGGER "ts_Basic_timest01"
BEFORE INSERT OR UPDATE ON "Basic"
FOR EACH ROW WHEN (new."timest" IS NULL)
-BEGIN
+BEGIN
SELECT sysdate INTO :new."timest" FROM dual;
END;
/
like (
$sql,
- qr/^\s*CREATE TABLE/m, #assume there is at least one create table statement
+ qr/^\s*CREATE TABLE/m, #assume there is at least one create table statement
"Received some meaningful output from the producer",
);
}
table => $table,
data_type => 'geometry',
extra => {
- dimensions => 2,
- geometry_type => 'POINT',
- srid => -1
- },
+ dimensions => 2,
+ geometry_type => 'POINT',
+ srid => -1
+ },
default_value => undef,
is_auto_increment => 0,
is_nullable => 1,
table => $table,
data_type => 'geography',
extra => {
- geography_type => 'POINT',
- srid => -1
- },
+ geography_type => 'POINT',
+ srid => -1
+ },
default_value => undef,
is_auto_increment => 0,
is_nullable => 1,
price numeric
);
- -- drop a column, to not have a linear id
+ -- drop a column, to not have a linear id
-- When the table t_test1 is created, f_last get id 5 but
-- after this drop, there is only 4 columns.
alter table sqlt_test1 drop column f_to_drop;
options: [% index.options %]
is_valid: [% index.is_valid %]
[% END %]
-
+
Constraints
[%- FOREACH constraint = table.get_constraints %]
[% constraint.name OR "?" %]
--- /dev/null
+Schema:
+Database:
+
+Foo: bar
+Hello: world
+
+Table: Basic
+==========================================================================
+
+Fields
+ id
+ data_type: int
+ size: 10
+ is_nullable: 0
+ default_value:
+ is_primary_key: 1
+ is_unique: 0
+ is_auto_increment: 1
+ is_foreign_key: 0
+ foreign_key_reference:
+ is_valid: 1
+ order: 1
+ table: Basic
+
+ title
+ data_type: varchar
+ size: 100
+ is_nullable: 0
+ default_value: hello
+ is_primary_key: 0
+ is_unique: 1
+ is_auto_increment: 0
+ is_foreign_key: 0
+ foreign_key_reference:
+ is_valid: 1
+ order: 2
+ table: Basic
+
+ description
+ data_type: text
+ size: 0
+ is_nullable: 1
+ default_value:
+ is_primary_key: 0
+ is_unique: 0
+ is_auto_increment: 0
+ is_foreign_key: 0
+ foreign_key_reference:
+ is_valid: 1
+ order: 3
+ table: Basic
+
+ email
+ data_type: varchar
+ size: 500
+ is_nullable: 1
+ default_value:
+ is_primary_key: 0
+ is_unique: 1
+ is_auto_increment: 0
+ is_foreign_key: 0
+ foreign_key_reference:
+ is_valid: 1
+ order: 4
+ table: Basic
+
+ explicitnulldef
+ data_type: varchar
+ size: 0
+ is_nullable: 1
+ default_value:
+ is_primary_key: 0
+ is_unique: 0
+ is_auto_increment: 0
+ is_foreign_key: 0
+ foreign_key_reference:
+ is_valid: 1
+ order: 5
+ table: Basic
+
+ explicitemptystring
+ data_type: varchar
+ size: 0
+ is_nullable: 1
+ default_value:
+ is_primary_key: 0
+ is_unique: 0
+ is_auto_increment: 0
+ is_foreign_key: 0
+ foreign_key_reference:
+ is_valid: 1
+ order: 6
+ table: Basic
+
+ emptytagdef
+ data_type: varchar
+ size: 0
+ is_nullable: 1
+ default_value:
+ is_primary_key: 0
+ is_unique: 0
+ is_auto_increment: 0
+ is_foreign_key: 0
+ foreign_key_reference:
+ is_valid: 1
+ order: 7
+ table: Basic
+
+ another_id
+ data_type: int
+ size: 10
+ is_nullable: 1
+ default_value: 2
+ is_primary_key: 0
+ is_unique: 0
+ is_auto_increment: 0
+ is_foreign_key: 1
+ foreign_key_reference: Another
+ is_valid: 1
+ order: 8
+ table: Basic
+
+ timest
+ data_type: timestamp
+ size: 0
+ is_nullable: 1
+ default_value:
+ is_primary_key: 0
+ is_unique: 0
+ is_auto_increment: 0
+ is_foreign_key: 0
+ foreign_key_reference:
+ is_valid: 1
+ order: 9
+ table: Basic
+
+
+Indices
+ titleindex
+ table: Basic
+ fields: title
+ type: NORMAL
+ options:
+ is_valid: 1
+
+
+Constraints
+ ?
+ type: PRIMARY KEY
+ fields: id
+ expression:
+ match_type:
+ reference_fields:
+ reference_table:
+ deferrable: 1
+ on_delete:
+ on_update:
+ options:
+ is_valid: 1
+
+ emailuniqueindex
+ type: UNIQUE
+ fields: email
+ expression:
+ match_type:
+ reference_fields:
+ reference_table:
+ deferrable: 1
+ on_delete:
+ on_update:
+ options:
+ is_valid: 1
+
+ very_long_index_name_on_title_field_which_should_be_truncated_for_various_rdbms
+ type: UNIQUE
+ fields: title
+ expression:
+ match_type:
+ reference_fields:
+ reference_table:
+ deferrable: 1
+ on_delete:
+ on_update:
+ options:
+ is_valid: 1
+
+ ?
+ type: FOREIGN KEY
+ fields: another_id
+ expression:
+ match_type:
+ reference_fields: id
+ reference_table: Another
+ deferrable: 1
+ on_delete:
+ on_update:
+ options:
+ is_valid: 1
+
+Table: Another
+==========================================================================
+
+Fields
+ id
+ data_type: int
+ size: 10
+ is_nullable: 0
+ default_value:
+ is_primary_key: 1
+ is_unique: 0
+ is_auto_increment: 1
+ is_foreign_key: 0
+ foreign_key_reference:
+ is_valid: 1
+ order: 1
+ table: Another
+
+ num
+ data_type: numeric
+ size: 10,2
+ is_nullable: 1
+ default_value:
+ is_primary_key: 0
+ is_unique: 0
+ is_auto_increment: 0
+ is_foreign_key: 0
+ foreign_key_reference:
+ is_valid: 1
+ order: 2
+ table: Another
+
+
+Indices
+
+Constraints
+ ?
+ type: PRIMARY KEY
+ fields: id
+ expression:
+ match_type:
+ reference_fields:
+ reference_table:
+ deferrable: 1
+ on_delete:
+ on_update:
+ options:
+ is_valid: 1
+
--- /dev/null
+Table: person
+ Primary Key: person_id
+ Foreign Keys:
+ Data Fields: name, age, weight, iq, description
+
+Table: pet
+ Primary Key: pet_id, person_id
+ Foreign Keys:
+ Data Fields: name, age
+
use_ok( "SQL::Translator::Producer::SQLite" );
# This test reproduces a bug in SQL::Translator::Producer::SQLite.
-#
+#
# When tables are created their names are not added to %global_names, and
# may be duplicated.
#
# SQL::Translator::Producer::SQLite version 1.59.
# compliments of SymKat <symkat@symkat.com>
-
+
my $output = SQL::Translator
sub has_dupes {
my ( @list ) = @_;
my %hist;
-
+
for my $elem ( @list ) {
return 0 if exists $hist{$elem};
$hist{$elem} = 1;
--- /dev/null
+use warnings;
+use strict;
+
+use Test::More;
+eval "use Test::EOL 1.1";
+plan skip_all => 'Test::EOL 1.1 required' if $@;
+
+Test::EOL::all_perl_files_ok({ trailing_whitespace => 1},
+ qw|lib t xt script share/DiaUml|,
+);
+
+# FIXME - Test::EOL declares 'no_plan' which conflicts with done_testing
+# https://github.com/schwern/test-more/issues/14
+#done_testing;
--- /dev/null
+use warnings;
+use strict;
+
+use Test::More;
+
+eval "use Test::NoTabs 1.1";
+plan skip_all => 'Test::NoTabs 1.1 required' if $@;
+
+Test::NoTabs::all_perl_files_ok(
+ qw|lib t xt script share/DiaUml|,
+);
+
+# FIXME - Test::NoTabs declares 'no_plan' which conflicts with done_testing
+# https://github.com/schwern/test-more/issues/14
+#done_testing;