Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Oracle producer add missing functions #143

Merged
merged 19 commits into from
Feb 23, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
ca601db
Added support for CURRENT_TIMESTAMP as a default value when parsing O…
hazardv Aug 10, 2022
0d8ce8f
Added tests to verify changes to oracle parser.
hazardv Aug 10, 2022
dbd1da1
Split the creation of contraints out from the creation of the table a…
hazardv Aug 18, 2022
929ae33
Missing a few small things
hazardv Aug 18, 2022
ed59a4d
Added drop_field to Oracle.pm and added alter constraint testing.
hazardv Aug 19, 2022
cdb544f
Added drop_table functionality along with related tests.
hazardv Aug 22, 2022
22a15de
Make sure the sqlt_args actually get passed in to the SQL::Translator…
hazardv Aug 24, 2022
ab42ef8
Removed batch alter stuff from Oracle.pm. It was just complicating th…
hazardv Aug 24, 2022
df7e62f
All quoting is working consistent to how it works for MySQL and SQLSe…
hazardv Aug 25, 2022
c90a599
Fixed issue with drop FK constraint syntax
hazardv Sep 7, 2022
b371f16
Fixed restriction stopping change of NOT NULL to NULL for non CLOB fi…
hazardv Sep 8, 2022
b14da74
Removed commented out section of code.
hazardv Sep 9, 2022
d2d080c
fixed issue with alter_drop_constraint when dropping unnamed primary …
hazardv Sep 26, 2022
2d47b5c
Reverted change to passing of $options and fixed test plan.
hazardv Sep 29, 2022
b4a8ca7
Added debug statements to figure out constraint order issue
hazardv Oct 5, 2022
a32992d
Separated FK_defs out so things would play nice and modified 51-xml-t…
hazardv Oct 5, 2022
090b5b4
Corrected quoting on index fields, updated 51-xml-to-oracle_quoted.t …
hazardv Oct 5, 2022
74c0312
Corrected changes previously made to 55-oracle-producer.t in error.
hazardv Oct 5, 2022
2a66d69
Removed some unnecessary debug comments.
hazardv Oct 5, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/SQL/Translator/Diff.pm
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ sub schema_diff {
$options ||= {};

my $obj = SQL::Translator::Diff->new( {
%$options,
sqlt_args => $options,
rabbiveesh marked this conversation as resolved.
Show resolved Hide resolved
source_schema => $source_schema,
target_schema => $target_schema,
output_db => $output_db
Expand Down
155 changes: 57 additions & 98 deletions lib/SQL/Translator/Producer/Oracle.pm
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,8 @@ $DEBUG = 0 unless defined $DEBUG;

use base 'SQL::Translator::Producer';
use SQL::Translator::Schema::Constants;
use SQL::Translator::Utils qw(header_comment batch_alter_table_statements);
use SQL::Translator::Utils qw(header_comment);
use Data::Dumper;

my %translate = (
#
Expand Down Expand Up @@ -390,23 +391,9 @@ sub create_table {
push @field_defs, 'CONSTRAINT '.$index_name.' PRIMARY KEY '.
'(' . join( ', ', @fields ) . ')';
}
elsif ( $index_type eq NORMAL ) {
$index_name = $index_name ? mk_name( $index_name )
: mk_name( $table_name, $index_name || 'i' );
$index_name = quote($index_name, $qf);
push @index_defs,
"CREATE INDEX $index_name on $table_name_q (".
join( ', ', @fields ).
")$index_options";
}
elsif ( $index_type eq UNIQUE ) {
$index_name = $index_name ? mk_name( $index_name )
: mk_name( $table_name, $index_name || 'i' );
$index_name = quote($index_name, $qf);
push @index_defs,
"CREATE UNIQUE INDEX $index_name on $table_name_q (".
join( ', ', @fields ).
")$index_options";
elsif ($index_type eq NORMAL or $index_type eq UNIQUE) {
warn "CAlling create index with options: " . Dumper($options) . "\n";
hazardv marked this conversation as resolved.
Show resolved Hide resolved
push @index_defs, create_index($index, $options, $index_options);
}
else {
warn "Unknown index type ($index_type) on table $table_name.\n"
Expand Down Expand Up @@ -465,12 +452,12 @@ sub alter_field {
sub drop_field
{
my ($old_field, $options) = @_;

my $table_name = quote($old_field->table->name);
my $qi = $options->{quote_identifiers};
my $table_name = quote($old_field->table->name, $qi);

my $out = sprintf('ALTER TABLE %s DROP COLUMN %s',
$table_name,
quote($old_field->name));
quote($old_field->name, $qi));

return $out;
}
Expand Down Expand Up @@ -668,19 +655,20 @@ sub create_field {
push @trigger_defs, $trigger;
}

if ( lc $field->data_type eq 'timestamp' ) {
my $base_name = $table_name . "_". $field_name;
my $trig_name = quote(mk_name( $base_name, 'ts' ), $qt);
my $trigger =
"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".
" SELECT sysdate INTO :new.$field_name_q FROM dual;\n".
"END;\n";

push @trigger_defs, $trigger;
}
# Do not create a trigger to insert sysdate to all timestamp fields
# if ( lc $field->data_type eq 'timestamp' ) {
hazardv marked this conversation as resolved.
Show resolved Hide resolved
# my $base_name = $table_name . "_". $field_name;
# my $trig_name = quote(mk_name( $base_name, 'ts' ), $qt);
# my $trigger =
# "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".
# " SELECT sysdate INTO :new.$field_name_q FROM dual;\n".
# "END;\n";

# push @trigger_defs, $trigger;
# }

push @field_defs, $field_def;

Expand All @@ -695,93 +683,64 @@ sub create_field {

}

sub batch_alter_table {
my ($table, $diff_hash, $options) = @_;

my %fks_to_alter;
my %fks_to_drop = map {
$_->type eq FOREIGN_KEY
? ( $_->name => $_ )
: ( )
} @{$diff_hash->{alter_drop_constraint} };

my %fks_to_create = map {
if ( $_->type eq FOREIGN_KEY) {
$fks_to_alter{$_->name} = $fks_to_drop{$_->name} if $fks_to_drop{$_->name};
( $_->name => $_ );
} else { ( ) }
} @{$diff_hash->{alter_create_constraint} };

my @drop_stmt;
if (scalar keys %fks_to_alter) {
$diff_hash->{alter_drop_constraint} = [
grep { !$fks_to_alter{$_->name} } @{ $diff_hash->{alter_drop_constraint} }
];

@drop_stmt = batch_alter_table($table, { alter_drop_constraint => [ values %fks_to_alter ] }, $options);

}

my @stmts = batch_alter_table_statements($diff_hash, $options);

# rename_table makes things a bit more complex
my $renamed_from = "";
$renamed_from = quote($diff_hash->{rename_table}[0][0]->name)
if $diff_hash->{rename_table} && @{$diff_hash->{rename_table}};

return unless @stmts;
# Just zero or one stmts. return now
return (@drop_stmt,@stmts) unless @stmts > 1;

# Now strip off the 'ALTER TABLE xyz' of all but the first one

my $table_name = quote($table->name);

my $re = $renamed_from
? qr/^ALTER TABLE (?:\Q$table_name\E|\Q$renamed_from\E) /
: qr/^ALTER TABLE \Q$table_name\E /;
sub drop_table {
my ($table, $options) = @_;

my $first = shift @stmts;
my ($alter_table) = $first =~ /($re)/;
my @foreign_key_constraints = grep { $_->type eq 'FOREIGN KEY' } $table->get_constraints;
my @statements;
for my $constraint(@foreign_key_constraints) {
push @statements, alter_drop_constraint($constraint);
}

my $padd = " " x length($alter_table);
return @statements, 'DROP TABLE ' . quote($table);
}

return @drop_stmt, join( ",\n", $first, map { s/$re//; $padd . $_ } @stmts);
sub alter_create_index {
my ($index, $options) = @_;
return create_index($index, $options);
}

sub create_index {
my ( $index, $options, $index_options) = @_;
my $qf = $options->{quote_field_names} || $options->{quote_identifiers};
my $qt = $options->{quote_table_names} || $options->{quote_identifiers};
return join(
' ',
map { $_ || () }
'CREATE',
lc $index->type eq 'normal' ? 'INDEX' : $index->type . ' INDEX',
$index->name ? quote($index->name, $qf): '',
'ON',
quote($index->table, $qt),
'(' . join( ', ', map { quote($_) } $index->fields ) . ")$index_options"
);
}

sub drop_table {
my ($table, $options) = @_;

return (
# Drop (foreign key) constraints so table drops cleanly
batch_alter_table(
$table, { alter_drop_constraint => [ grep { $_->type eq 'FOREIGN KEY' } $table->get_constraints ] }, $options
),
'DROP TABLE ' . quote($table),
);
sub alter_drop_index {
my ($index, $options) = @_;
return 'DROP INDEX ' . $index->name;
}

sub alter_drop_constraint {
my ($c, $options) = @_;

my $table_name = quote($c->table->name);
my $qi = $options->{quote_identifiers};
my $table_name = quote($c->table->name, $qi);

my @out = ('ALTER','TABLE',$table_name,'DROP');
if($c->type eq PRIMARY_KEY) {
push @out, $c->type;
}
else {
push @out, ($c->type eq FOREIGN_KEY ? $c->type : "CONSTRAINT"),
quote($c->name);
quote($c->name, $qi);
}
return join(' ',@out);
}

sub alter_create_constraint {
my ($index, $options) = @_;

my $table_name = quote($index->table->name);
my $qi = $options->{quote_identifiers};
my $table_name = quote($index->table->name, $qi);
return join( ' ',
'ALTER TABLE',
$table_name,
Expand Down
66 changes: 66 additions & 0 deletions t/54-oracle-sql-diff.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#!/usr/bin/perl

use FindBin qw/$Bin/;
use Test::More;
use Test::SQL::Translator;
use Test::Exception;
use Data::Dumper;
use SQL::Translator;
use SQL::Translator::Diff;

BEGIN {
maybe_plan(6, 'SQL::Translator::Producer::Oracle');
}

my $schema1 = $Bin.'/data/oracle/schema-1.5.sql';
my $schema2 = $Bin.'/data/oracle/schema-1.6.sql';

open my $io1, '<', $schema1 or die $!;
open my $io2, '<', $schema2 or die $!;

my ($yaml1, $yaml2);
{
local $/ = undef;
$sql1 = <$io1>;
$sql2 = <$io2>;
};

close $io1;
close $io2;

my $s = SQL::Translator->new(from => 'Oracle');
$s->parser->($s,$sql1);

my $t = SQL::Translator->new(from => 'Oracle', debug => 1);
$t->parser->($t,$sql2);

my $d = SQL::Translator::Diff->new
({
output_db => 'Oracle',
target_db => 'Oracle',
source_schema => $s->schema,
target_schema => $t->schema,
sqlt_args => {quote_identifiers => 1}
});


my $diff = $d->compute_differences->produce_diff_sql || die $d->error;

ok($diff, 'Diff generated.');

warn "The diff is: " . Dumper($diff);
hazardv marked this conversation as resolved.
Show resolved Hide resolved

like($diff, '/CREATE TABLE t_group/', 'CREATE TABLE t_group generated');

like($diff, '/ALTER TABLE t_category DROP CONSTRAINT t_category_display_name/', 'DROP constraint display_name generated');

like($diff, '/ALTER TABLE t_message MODIFY \( alert_id number\(11\) \)/', 'MODIFY alert_id generated');

like($diff, '/CREATE INDEX t_user_groups_idx_user_id ON t_user_groups \(user_id\)/', 'CREATE INDEX generated');
# like($diff, '/ALTER TABLE t_category_defaults DROP FOREIGN KEY t_category_defaults_user_id/', 'DROP FOREIGN KEY constraint generated');

# like($diff, '/ALTER TABLE t_user_groups ADD CONSTRAINT t_user_groups_group_id_fk FOREIGN KEY \(group_id\) REFERENCES t_group \(group_id\) ON DELETE CASCADE/', 'ADD FOREIGN KEY constraint generated');

# like($diff, '/ADD CONSTRAINT other_check CHECK \(other BETWEEN 100 and 99999\)/', 'ADD check constraint generated');

# like($diff, '/DROP TABLE customer/', 'DROP TABLE customer generated');