aboutsummaryrefslogtreecommitdiff
path: root/contrib/oracle/Ora2Pg.pm
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/oracle/Ora2Pg.pm')
-rw-r--r--contrib/oracle/Ora2Pg.pm718
1 files changed, 564 insertions, 154 deletions
diff --git a/contrib/oracle/Ora2Pg.pm b/contrib/oracle/Ora2Pg.pm
index 95439b88f73..91b9dff757d 100644
--- a/contrib/oracle/Ora2Pg.pm
+++ b/contrib/oracle/Ora2Pg.pm
@@ -61,7 +61,9 @@ or if you only want to extract some tables:
datasource => $dbsrc, # Database DBD datasource
user => $dbuser, # Database user
password => $dbpwd, # Database password
- tables => \@tables, # Tables to extract
+ tables => \@tables,
+ or # Tables to extract
+ tables => [('tab1','tab2')],
debug => 1 # To show somethings when running
);
@@ -82,10 +84,14 @@ or if you only want to extract tables 10 to 20:
datasource => $dbsrc, # Database DBD datasource
user => $dbuser, # Database user
password => $dbpwd, # Database password
- min => 10 # Begin extraction at indice 10
+ min => 10, # Begin extraction at indice 10
max => 20 # End extraction at indice 20
);
+To choose a particular schema just set the following option to your schema name :
+
+ schema => 'APPS'
+
To know at which indices table can be found during extraction use the option:
showtableid => 1
@@ -94,8 +100,29 @@ To extract all views set the option type as follow:
type => 'VIEW'
+To extract all grants set the option type as follow:
+
+ type => 'GRANT'
+
+To extract all sequences set the option type as follow:
+
+ type => 'SEQUENCE'
+
+To extract all triggers set the option type as follow:
+
+ type => 'TRIGGER'
+
+To extract all functions set the option type as follow:
+
+ type => 'FUNCTION'
+
+To extract all procedures set the option type as follow:
+
+ type => 'PROCEDURE'
+
Default is table schema extraction
+ type => 'TABLE'
=head1 DESCRIPTION
@@ -110,9 +137,16 @@ I'm not a Oracle DBA so I don't really know something about its internal
structure so you may find some incorrect things. Please tell me what is
wrong and what can be better.
-It currently only dump the database schema, with primary, unique and
-foreign keys. I've tried to excluded internal system tables but perhaps
-not enougt, please let me know.
+It currently dump the database schema (tables, views, sequences, indexes, grants),
+with primary, unique and foreign keys into PostgreSQL syntax without editing the
+SQL code generated.
+
+Functions, procedures and triggers PL/SQL code generated must be reviewed to match
+the PostgreSQL syntax. Some usefull recommandation on porting Oracle to PostgreSQL
+can be found at http://techdocs.postgresql.org/ under the "Converting from other
+Databases to PostgreSQL" Oracle part. I just notice one thing more is that the
+trunc() function in Oracle is the same for number or date so be carefull when
+porting to PostgreSQL to use trunc() for number and date_trunc() for date.
=head1 ABSTRACT
@@ -123,13 +157,13 @@ the connection parameters to the Oracle database.
Features must include:
- - Database schema export, with unique, primary and foreign key.
+ - Database schema export (tables, views, sequences, indexes),
+ with unique, primary and foreign key.
- Grants/privileges export by user and group.
- - Indexes and unique indexes export.
- - Table or view selection (by name and max table) export.
- - Predefined function/trigger export (todo)
- - Data export (todo)
+ - Table selection (by name and max table) export.
+ - Predefined functions/triggers/procedures export.
- Sql query converter (todo)
+ - Data export (todo)
My knowledge regarding database is really poor especially for Oracle
so contribution is welcome.
@@ -152,7 +186,8 @@ Supported options are:
- datasource : DBD datasource (required)
- user : DBD user (optional with public access)
- password : DBD password (optional with public access)
- - type : Type of data to extract, can be TABLE (default) or VIEW
+ - schema : Oracle internal schema to extract
+ - type : Type of data to extract, can be TABLE,VIEW,GRANT,SEQUENCE,TRIGGER,FUNCTION,PROCEDURE
- debug : Print the current state of the parsing
- tables : Extract only the given tables (arrayref)
- showtableid : Display only the table indice during extraction
@@ -206,7 +241,7 @@ sub export_schema
#### Private subroutines
-=head1 PUBLIC METHODS
+=head1 PRIVATE METHODS
=head2 _init HASH_OPTIONS
@@ -233,6 +268,9 @@ sub _init
$self->{limited} = ();
$self->{limited} = $options{tables} if ($options{tables});
+ $self->{schema} = '';
+ $self->{schema} = $options{schema} if ($options{schema});
+
$self->{min} = 0;
$self->{min} = $options{min} if ($options{min});
@@ -248,10 +286,23 @@ sub _init
# Retreive all table informations
if (!exists $options{type} || ($options{type} eq 'TABLE')) {
$self->_tables();
- } else {
+ } elsif ($options{type} eq 'VIEW') {
$self->{dbh}->{LongReadLen} = 100000;
$self->_views();
+ } elsif ($options{type} eq 'GRANT') {
+ $self->_grants();
+ } elsif ($options{type} eq 'SEQUENCE') {
+ $self->_sequences();
+ } elsif ($options{type} eq 'TRIGGER') {
+ $self->{dbh}->{LongReadLen} = 100000;
+ $self->_triggers();
+ } elsif (($options{type} eq 'FUNCTION') || ($options{type} eq 'PROCEDURE')) {
+ $self->{dbh}->{LongReadLen} = 100000;
+ $self->_functions($options{type});
+ } else {
+ die "type option must be TABLE, VIEW, GRANT, SEQUENCE, TRIGGER, FUNCTION or PROCEDURE\n";
}
+ $self->{type} = $options{type};
# Disconnect from the database
$self->{dbh}->disconnect() if ($self->{dbh});
@@ -264,6 +315,84 @@ sub _init
sub DESTROY { }
+=head2 _grants
+
+This function is used to retrieve all privilege information.
+
+It extract all Oracle's ROLES to convert them as Postgres groups
+and search all users associated to these roles.
+
+Set the main hash $self->{groups}.
+Set the main hash $self->{grantss}.
+
+=cut
+
+sub _grants
+{
+ my ($self) = @_;
+
+print STDERR "Retrieving groups/users information...\n" if ($self->{debug});
+ $self->{users} = $self->_get_users();
+ $self->{groups} = $self->_get_roles();
+ $self->{grants} = $self->_get_all_grants();
+
+}
+
+
+=head2 _sequences
+
+This function is used to retrieve all sequences information.
+
+Set the main hash $self->{sequences}.
+
+=cut
+
+sub _sequences
+{
+ my ($self) = @_;
+
+print STDERR "Retrieving sequences information...\n" if ($self->{debug});
+ $self->{sequences} = $self->_get_sequences();
+
+}
+
+
+=head2 _triggers
+
+This function is used to retrieve all triggers information.
+
+Set the main hash $self->{triggers}.
+
+=cut
+
+sub _triggers
+{
+ my ($self) = @_;
+
+print STDERR "Retrieving triggers information...\n" if ($self->{debug});
+ $self->{triggers} = $self->_get_triggers();
+
+}
+
+
+=head2 _functions
+
+This function is used to retrieve all functions information.
+
+Set the main hash $self->{functions}.
+
+=cut
+
+sub _functions
+{
+ my ($self, $type) = @_;
+
+print STDERR "Retrieving functions information...\n" if ($self->{debug});
+ $self->{functions} = $self->_get_functions($type);
+
+}
+
+
=head2 _tables
This function is used to retrieve all table information.
@@ -288,10 +417,10 @@ main hash of the database structure :
It also call these other private subroutine to affect the main hash
of the database structure :
- @{$self->{tables}{$class_name}{column_info}} = &_column_info($self, $class_name);
- @{$self->{tables}{$class_name}{primary_key}} = &_primary_key($self, $class_name);
- @{$self->{tables}{$class_name}{unique_key}} = &_unique_key($self, $class_name);
- @{$self->{tables}{$class_name}{foreign_key}} = &_foreign_key($self, $class_name);
+ @{$self->{tables}{$class_name}{column_info}} = $self->_column_info($class_name);
+ @{$self->{tables}{$class_name}{primary_key}} = $self->_primary_key($class_name);
+ @{$self->{tables}{$class_name}{unique_key}} = $self->_unique_key($class_name);
+ @{$self->{tables}{$class_name}{foreign_key}} = $self->_foreign_key($class_name);
=cut
@@ -301,7 +430,8 @@ sub _tables
# Get all tables information given by the DBI method table_info
print STDERR "Retrieving table information...\n" if ($self->{debug});
- my $sth = $self->{dbh}->table_info or die $self->{dbh}->errstr;
+
+ my $sth = $self->_table_info or die $self->{dbh}->errstr;
my @tables_infos = $sth->fetchall_arrayref();
if ($self->{showtableid}) {
@@ -312,7 +442,7 @@ print STDERR "Retrieving table information...\n" if ($self->{debug});
}
return;
}
-
+my @done = ();
foreach my $table (@tables_infos) {
# Set the table information for each class found
my $i = 1;
@@ -320,7 +450,11 @@ print STDERR "Min table dump set to $self->{min}.\n" if ($self->{debug} && $self
print STDERR "Max table dump set to $self->{max}.\n" if ($self->{debug} && $self->{max});
foreach my $t (@$table) {
# Jump to desired extraction
- next if (${@$t}[2] =~ /\$/);
+if (grep(/^${@$t}[2]$/, @done)) {
+print STDERR "SSSSSS duplicate ${@$t}[0] - ${@$t}[1] - ${@$t}[2]\n";
+} else {
+push(@done, ${@$t}[2]);
+}
$i++, next if ($self->{min} && ($i < $self->{min}));
last if ($self->{max} && ($i > $self->{max}));
next if (($#{$self->{limited}} >= 0) && !grep(/^${@$t}[2]$/, @{$self->{limited}}));
@@ -349,19 +483,15 @@ print STDERR "Scanning ${@$t}[2] (@$t)...\n" if ($self->{debug});
$self->{tables}{${@$t}[2]}{field_name} = $sth->{NAME};
$self->{tables}{${@$t}[2]}{field_type} = $sth->{TYPE};
- @{$self->{tables}{${@$t}[2]}{column_info}} = &_column_info($self, ${@$t}[2]);
- @{$self->{tables}{${@$t}[2]}{primary_key}} = &_primary_key($self, ${@$t}[2]);
- @{$self->{tables}{${@$t}[2]}{unique_key}} = &_unique_key($self, ${@$t}[2]);
- @{$self->{tables}{${@$t}[2]}{foreign_key}} = &_foreign_key($self, ${@$t}[2]);
- ($self->{tables}{${@$t}[2]}{uniqueness}, $self->{tables}{${@$t}[2]}{indexes}) = &_get_indexes($self, ${@$t}[2]);
- $self->{tables}{${@$t}[2]}{grants} = &_get_table_privilege($self, ${@$t}[2]);
+ @{$self->{tables}{${@$t}[2]}{column_info}} = $self->_column_info(${@$t}[2]);
+ @{$self->{tables}{${@$t}[2]}{primary_key}} = $self->_primary_key(${@$t}[2]);
+ @{$self->{tables}{${@$t}[2]}{unique_key}} = $self->_unique_key(${@$t}[2]);
+ ($self->{tables}{${@$t}[2]}{foreign_link}, $self->{tables}{${@$t}[2]}{foreign_key}) = $self->_foreign_key(${@$t}[2]);
+ ($self->{tables}{${@$t}[2]}{uniqueness}, $self->{tables}{${@$t}[2]}{indexes}) = $self->_get_indexes(${@$t}[2]);
$i++;
}
}
-print STDERR "Retrieving groups/users information...\n" if ($self->{debug});
- $self->{groups} = &_get_roles($self);
-
}
@@ -377,8 +507,6 @@ It then set the main hash as follow:
# Definition of the view
$self->{views}{$table}{text} = $view_infos{$table};
- # Grants defined on the views
- $self->{views}{$table}{grants} = when I find how...
=cut
@@ -388,7 +516,7 @@ sub _views
# Get all views information
print STDERR "Retrieving views information...\n" if ($self->{debug});
- my %view_infos = &_get_views($self);
+ my %view_infos = $self->_get_views();
if ($self->{showtableid}) {
my $i = 1;
@@ -433,25 +561,180 @@ sub _get_sql_data
$sql_header .= "--\n";
$sql_header .= "-- This program is free software; you can redistribute it and/or modify it under\n";
$sql_header .= "-- the same terms as Perl itself.\n\n";
+ $sql_header .= "BEGIN TRANSACTION;\n\n";
my $sql_output = "";
# Process view only
- if (exists $self->{views}) {
+ if ($self->{type} eq 'VIEW') {
+print STDERR "Add views definition...\n" if ($self->{debug});
foreach my $view (sort keys %{$self->{views}}) {
- $sql_output .= "CREATE VIEW $view AS $self->{views}{$view}{text};\n";
+ $sql_output .= "CREATE VIEW \"\L$view\E\" AS $self->{views}{$view}{text};\n";
+ }
+
+ if (!$sql_output) {
+ $sql_output = "-- Nothing found of type $self->{type}\n";
+ } else {
+ $sql_output .= "\n";
}
- $sql_output .= "\n";
- return $sql_header . $sql_output;
+ return $sql_header . $sql_output . "\nEND TRANSACTION";
}
- my @groups = ();
- my @users = ();
- # Dump the database structure as an XML Schema defintion
+ # Process grant only
+ if ($self->{type} eq 'GRANT') {
+print STDERR "Add groups/users privileges...\n" if ($self->{debug});
+ # Add groups definition
+ my $groups = '';
+ my @users = ();
+ my @grps = ();
+ foreach (@{$self->{users}}) {
+ next if (exists $self->{groups}{"$_"});
+ next if ($self->{schema} && ($_ ne $self->{schema}));
+ $sql_header .= "CREATE USER $_ WITH PASSWORD 'secret';\n";
+ }
+ foreach my $role (sort keys %{$self->{groups}}) {
+ push(@grps, $role);
+ $groups .= "CREATE GROUP $role WITH USER " . join(',', @{$self->{groups}{$role}}) . ";\n";
+ }
+ $sql_header .= "\n" . $groups . "\n";
+
+ # Add privilege definition
+ my $grants = '';
+ foreach my $table (sort keys %{$self->{grants}}) {
+ $grants .= "REVOKE ALL ON $table FROM PUBLIC;\n";
+ foreach my $priv (sort keys %{$self->{grants}{$table}}) {
+ my $usr = '';
+ my $grp = '';
+ foreach my $user (@{$self->{grants}{$table}{$priv}}) {
+ if (grep(/^$user$/, @grps)) {
+ $grp .= "$user,";
+ } else {
+ $usr .= "$user,";
+ }
+ }
+ $grp =~ s/,$//;
+ $usr =~ s/,$//;
+ if ($grp) {
+ $grants .= "GRANT $priv ON $table TO GROUP $grp;\n";
+ } else {
+ $grants .= "GRANT $priv ON $table TO $usr;\n";
+ }
+ }
+ }
+
+ if (!$grants) {
+ $$grants = "-- Nothing found of type $self->{type}\n";
+ }
+
+ $sql_output .= "\n" . $grants . "\n";
+
+ return $sql_header . $sql_output . "\nEND TRANSACTION";
+ }
+
+ # Process sequences only
+ if ($self->{type} eq 'SEQUENCE') {
+print STDERR "Add sequences definition...\n" if ($self->{debug});
+ foreach my $seq (@{$self->{sequences}}) {
+ my $cache = 1;
+ $cache = $seq->[5] if ($seq->[5]);
+ my $cycle = '';
+ $cycle = ' CYCLE' if ($seq->[6] eq 'Y');
+ if ($seq->[2] > 2147483646) {
+ $seq->[2] = 2147483646;
+ }
+ if ($seq->[1] < -2147483647) {
+ $seq->[1] = -2147483647;
+ }
+ $sql_output .= "CREATE SEQUENCE \L$seq->[0]\E INCREMENT $seq->[3] MINVALUE $seq->[1] MAXVALUE $seq->[2] START $seq->[4] CACHE $cache$cycle;\n";
+ }
+
+ if (!$sql_output) {
+ $sql_output = "-- Nothing found of type $self->{type}\n";
+ }
+
+ return $sql_header . $sql_output . "\nEND TRANSACTION";
+ }
+
+ # Process triggers only. PL/SQL code is pre-converted to PL/PGSQL following
+ # the recommendation of Roberto Mello, see http://techdocs.postgresql.org/
+ # Oracle's PL/SQL to PostgreSQL PL/pgSQL HOWTO
+ if ($self->{type} eq 'TRIGGER') {
+print STDERR "Add triggers definition...\n" if ($self->{debug});
+ foreach my $trig (@{$self->{triggers}}) {
+ $trig->[1] =~ s/ EACH ROW//;
+ chop($trig->[4]);
+ chomp($trig->[4]);
+ # Check if it's a pg rule
+ if ($trig->[1] =~ /INSTEAD OF/) {
+ $sql_output .= "CREATE RULE \L$trig->[0]\E AS\n\tON \L$trig->[3]\E\n\tDO INSTEAD\n(\n\t$trig->[4]\n);\n\n";
+ } else {
+
+ #--------------------------------------------
+ # PL/SQL to PL/PGSQL code conversion
+ #--------------------------------------------
+ # Change NVL to COALESCE
+ #$trig->[4] =~ s/NVL\(/coalesce(/igs;
+ # Change trunc() to date_trunc('day', field)
+ # Trunc is replaced with date_trunc if we find date in the name of the value
+ # because Oracle have the same trunc function on number and date type :-(((
+ #$trig->[4] =~ s/trunc\(([^\)]*date[^\)]*)\)/date_trunc('day', $1)/igs;
+ # Change SYSDATE to 'now'
+ #$trig->[4] =~ s/SYSDATE/CURRENT_TIMESTAMP/igs;
+ # Change nextval on sequence
+ # Oracle's sequence grammar is sequence_name.nextval.
+ # Postgres's sequence grammar is nextval('sequence_name').
+ #$trig->[4] =~ s/(\w+)\.nextval/nextval('$1')/isg;
+ # Escaping Single Quotes
+ #$trig->[4] =~ s/'/''/sg;
+
+ $sql_output .= "CREATE FUNCTION pg_fct_\L$trig->[0]\E () RETURNS OPAQUE AS '\n$trig->[4]\n' LANGUAGE 'plpgsql'\n\n";
+ $sql_output .= "CREATE TRIGGER \L$trig->[0]\E\n\t$trig->[1] $trig->[2] ON \L$trig->[3]\E FOR EACH ROW\n\tEXECUTE PROCEDURE pg_fct_\L$trig->[0]\E();\n\n";
+ }
+ }
+
+ if (!$sql_output) {
+ $sql_output = "-- Nothing found of type $self->{type}\n";
+ }
+
+ return $sql_header . $sql_output . "\nEND TRANSACTION";
+ }
+
+ # Process functions only
+ if (($self->{type} eq 'FUNCTION') || ($self->{type} eq 'PROCEDURE')) {
+print STDERR "Add functions definition...\n" if ($self->{debug});
+ foreach my $fct (sort keys %{$self->{functions}}) {
+ my @tmp = ();
+ if ($self->{functions}{$fct} =~ /^[\s\t]*function/is) {
+ #$self->{functions}{$fct} =~ /function[\s\n\t]*$fct[\s\n\t]*\(([^\)]*)\)/is;
+ $self->{functions}{$fct} =~ /function[\s\n\t]*$fct[\s\n\t]*\(([^\)]*)\)[\s\n\t]*is/is;
+ @tmp = split(/\n/, $1);
+ } else {
+ #$self->{functions}{$fct} =~ /procedure[\s\n\t]*$fct[\s\n\t]*\(([^\)]*)\)/is;
+ $self->{functions}{$fct} =~ /procedure[\s\n\t]*$fct[\s\n\t]*\(([^\)]*)\)[\s\n\t]*is\W/is;
+ @tmp = split(/\n/, $1);
+ }
+ my @argu = split(/,/, join(' ', @tmp));
+ map { s/^.* in //is } @argu;
+ map { s/^.* out //is } @argu;
+ map { $_ = $self->_sql_type(uc($_)) } @argu;
+ $self->{functions}{$fct} =~ /return ([^\s]*) is/is;
+ $self->{functions}{$fct} = "-- Oracle function declaration, please edit to match PostgreSQL syntax.\n$self->{functions}{$fct}";
+ $sql_output .= "-- PostgreSQL possible function declaration, please edit to match your needs.\nCREATE FUNCTION \L$fct\E(" . join(',', @argu) . ") RETURNS " . $self->_sql_type(uc($1)) . " AS '\n$self->{functions}{$fct}\n' LANGUAGE 'sql'\n\n";
+ }
+
+ if (!$sql_output) {
+ $sql_output = "-- Nothing found of type $self->{type}\n";
+ }
+
+ return $sql_header . $sql_output . "\nEND TRANSACTION";
+ }
+
+
+
+ # Dump the database structure
foreach my $table (keys %{$self->{tables}}) {
print STDERR "Dumping table $table...\n" if ($self->{debug});
- # Can be: TABLE, VIEW, SYSTEM TABLE, GLOBAL TEMPORARY,
$sql_output .= "CREATE ${$self->{tables}{$table}{table_info}}[1] \"\L$table\E\" (\n";
my $sql_ukey = "";
my $sql_pkey = "";
@@ -460,11 +743,11 @@ print STDERR "Dumping table $table...\n" if ($self->{debug});
next if (${$f}[0] ne "${$self->{tables}{$table}{field_name}}[$i]");
my $type = $self->_sql_type(${$f}[1], ${$f}[2]);
$type = "${$f}[1], ${$f}[2]" if (!$type);
- $sql_output .= "\t${$f}[0] $type";
+ $sql_output .= "\t\"\L${$f}[0]\E\" $type";
# Set the primary key definition
foreach my $k (@{$self->{tables}{$table}{primary_key}}) {
next if ($k ne "${$f}[0]");
- $sql_pkey .= "$k,";
+ $sql_pkey .= "\"\L$k\E\",";
last;
}
if (${$f}[4] ne "") {
@@ -475,7 +758,7 @@ print STDERR "Dumping table $table...\n" if ($self->{debug});
# Set the unique key definition
foreach my $k (@{$self->{tables}{$table}{unique_key}}) {
next if ( ($k ne "${$f}[0]") || (grep(/^$k$/, @{$self->{tables}{$table}{primary_key}})) );
- $sql_ukey .= "$k,";
+ $sql_ukey .= "\"\L$k\E\",";
last;
}
$sql_output .= ",\n";
@@ -488,58 +771,39 @@ print STDERR "Dumping table $table...\n" if ($self->{debug});
$sql_output .= "\tPRIMARY KEY ($sql_pkey),\n" if ($sql_pkey);
# Add constraint definition
+ my @done = ();
foreach my $h (@{$self->{tables}{$table}{foreign_key}}) {
- foreach my $link (keys %{$h}) {
- my ($reftable,$desttable) = split(/->/, $link);
- next if ($reftable ne $table);
- my $localcols = '';
- foreach my $i (0 .. $#{${$h}{$link}{local}}) {
- my $destname = "$desttable";
- my $remote = "${${$h}{$link}{remote}}[$i]";
- my $local = "${${$h}{$link}{local}}[$i]";
- $sql_output .= "\tCONSTRAINT ${i}_\L$table\E_fk FOREIGN KEY ($local) REFERENCES $desttable ($remote),\n";
- }
+ next if (grep(/^$h->[0]$/, @done));
+ my $desttable = '';
+ foreach (keys %{$self->{tables}{$table}{foreign_link}{$h->[0]}{remote}}) {
+ $desttable .= "$_";
}
+ push(@done, $h->[0]);
+ $sql_output .= "\tCONSTRAINT \L$h->[0]\E FOREIGN KEY (" . lc(join(',', @{$self->{tables}{$table}{foreign_link}{$h->[0]}{local}})) . ") REFERENCES \L$desttable\E (" . lc(join(',', @{$self->{tables}{$table}{foreign_link}{$h->[0]}{remote}{$desttable}})) . ")";
+ $sql_output .= " MATCH $h->[2]" if ($h->[2]);
+ $sql_output .= " ON DELETE $h->[3]";
+ $sql_output .= " $h->[4]";
+ $sql_output .= " INITIALLY $h->[5],\n";
+
}
$sql_output =~ s/,$//;
$sql_output .= ");\n";
foreach my $idx (keys %{$self->{tables}{$table}{indexes}}) {
+ map { s/^/"/ } @{$self->{tables}{$table}{indexes}{$idx}};
+ map { s/$/"/ } @{$self->{tables}{$table}{indexes}{$idx}};
my $columns = join(',', @{$self->{tables}{$table}{indexes}{$idx}});
my $unique = '';
$unique = ' UNIQUE' if ($self->{tables}{$table}{uniqueness}{$idx} eq 'UNIQUE');
- $sql_output .= "CREATE$unique INDEX \L$idx\E ON \L$table\E (\L$columns\E);\n";
- }
- # Add grant on this table
- $sql_output .= "REVOKE ALL ON $table FROM PUBLIC;\n";
- foreach my $grp (keys %{$self->{tables}{$table}{grants}}) {
- if (exists $self->{groups}{$grp}) {
- $sql_output .= "GRANT " . join(',', @{$self->{tables}{$table}{grants}{$grp}}) . " ON $table TO GROUP $grp;\n";
- push(@groups, $grp) if (!grep(/^$grp$/, @groups));
- } else {
- $sql_output .= "GRANT " . join(',', @{$self->{tables}{$table}{grants}{$grp}}) . " ON $table TO $grp;\n";
- push(@users, $grp) if (!grep(/^$grp$/, @users));
- }
+ $sql_output .= "CREATE$unique INDEX \"\L$idx\E\" ON \"\L$table\E\" (\L$columns\E);\n";
}
$sql_output .= "\n";
}
- # Add privilege definition
-print STDERR "Add groups/users privileges...\n" if ($self->{debug} && exists $self->{groups});
- my $grants = '';
- foreach my $role (@groups) {
- next if (!exists $self->{groups}{$role});
- $grants .= "CREATE GROUP $role;\n";
- $grants .= "ALTER GROUP $role ADD USERS " . join(',', @{$self->{groups}{$role}}) . ";\n";
- foreach my $u (@{$self->{groups}{$role}}) {
- push(@users, $u) if (!grep(/^$u$/, @users));
- }
+ if (!$sql_output) {
+ $sql_output = "-- Nothing found of type TABLE\n";
}
- foreach my $u (@users) {
- $sql_header .= "CREATE USER $u WITH PASSWORD 'secret';\n";
- }
- $sql_header .= "\n" . $grants . "\n";
- return $sql_header . $sql_output;
+ return $sql_header . $sql_output . "\nEND TRANSACTION";
}
@@ -555,12 +819,12 @@ sub _sql_type
my ($self, $type, $len) = @_;
my %TYPE = (
- 'NUMBER' => 'double',
+ 'NUMBER' => 'float8',
'LONG' => 'integer',
'CHAR' => 'char',
'VARCHAR2' => 'varchar',
'DATE' => 'datetime',
- 'RAW' => 'binary',
+ 'RAW' => 'text',
'ROWID' => 'oid',
'LONG RAW' => 'binary',
);
@@ -575,7 +839,7 @@ sub _sql_type
} elsif (($type eq "CHAR") || ($type =~ /VARCHAR/)) {
return "$TYPE{$type}($len)";
} else {
- return "$TYPE{$type}($len)";
+ return "$TYPE{$type}";
}
} else {
return $TYPE{$type};
@@ -717,68 +981,79 @@ sub _foreign_key
{
my ($self, $table) = @_;
- my $sth = $self->{dbh}->prepare(<<END) or die $self->{dbh}->errstr;
-select cls.TABLE_NAME, clf.TABLE_NAME, cls.COLUMN_NAME, clf.COLUMN_NAME
-from all_constraints cns, all_cons_columns clf , all_cons_columns cls
-where cns.CONSTRAINT_TYPE='R'
-and cns.constraint_name=cls.constraint_name
-and clf.CONSTRAINT_NAME = cns.R_CONSTRAINT_NAME
-and clf.OWNER = cns.OWNER
-and clf.POSITION = clf.POSITION
-and cns.STATUS='ENABLED'
-and cns.TABLE_NAME='EVT_DEST_PROFILE'
-order by cns.CONSTRAINT_NAME, cls.position
-END
+ my $str = "SELECT CONSTRAINT_NAME,R_CONSTRAINT_NAME,SEARCH_CONDITION,DELETE_RULE,DEFERRABLE,DEFERRED FROM DBA_CONSTRAINTS WHERE CONSTRAINT_TYPE='R' AND STATUS='ENABLED' AND TABLE_NAME='$table'";
+ my $sth = $self->{dbh}->prepare($str) or die $self->{dbh}->errstr;
$sth->execute or die $sth->errstr;
my @data = ();
my %link = ();
+ my @tab_done = ();
while (my $row = $sth->fetch) {
- my @trig_info = split(/\\000/, ${@$row}[0]);
- # The first field is the name of the constraint, we
- # remove it because we use a table to table notation.
- my $trig_name = ${@$row}[0] . "->" . ${@$row}[1];
- push(@{$link{$trig_name}{local}}, ${@$row}[2]);
- push(@{$link{$trig_name}{remote}}, ${@$row}[3]);
+ next if (grep(/^$row->[0]$/, @tab_done));
+ push(@data, [ @$row ]);
+ push(@tab_done, $row->[0]);
+ my $sql = "SELECT DISTINCT COLUMN_NAME FROM DBA_CONS_COLUMNS WHERE CONSTRAINT_NAME='$row->[0]'";
+ my $sth2 = $self->{dbh}->prepare($sql) or die $self->{dbh}->errstr;
+ $sth2->execute or die $sth2->errstr;
+ my @done = ();
+ while (my $r = $sth2->fetch) {
+ if (!grep(/^$r->[0]$/, @done)) {
+ push(@{$link{$row->[0]}{local}}, $r->[0]);
+ push(@done, $r->[0]);
+ }
+ }
+ $sql = "SELECT DISTINCT TABLE_NAME,COLUMN_NAME FROM DBA_CONS_COLUMNS WHERE CONSTRAINT_NAME='$row->[1]'";
+ $sth2 = $self->{dbh}->prepare($sql) or die $self->{dbh}->errstr;
+ $sth2->execute or die $sth2->errstr;
+ @done = ();
+ while (my $r = $sth2->fetch) {
+ if (!grep(/^$r->[1]$/, @done)) {
+ push(@{$link{$row->[0]}{remote}{$r->[0]}}, $r->[1]);
+ push(@done, $r->[1]);
+ }
+ }
}
- push(@data, \%link);
- return @data;
+ return \%link, \@data;
}
-=head2 _get_table_privilege TABLE
+=head2 _get_users
-This function implements a Oracle-native table grants
-information.
+This function implements a Oracle-native users information.
-Return a hash of array of all users and their grants on the
-given table.
+Return a hash of all users as an array.
=cut
-sub _get_table_privilege
+sub _get_users
{
- my($self, $table) = @_;
-
- my @pg_grants = ('DELETE','INSERT','SELECT','UPDATE');
+ my($self) = @_;
- # Retrieve all ROLES defined in this database
- my $str = "SELECT GRANTEE, PRIVILEGE FROM DBA_TAB_PRIVS WHERE TABLE_NAME='$table' ORDER BY GRANTEE, PRIVILEGE";
+ # Retrieve all USERS defined in this database
+ my $str = "SELECT USERNAME FROM DBA_USERS";
+ if (!$self->{schema}) {
+ $str .= " WHERE USERNAME <> 'SYS' AND USERNAME <> 'SYSTEM' AND USERNAME <> 'DBSNMP'";
+ } else {
+ $str .= " WHERE USERNAME = '$self->{schema}'";
+ }
+ $str .= " ORDER BY USERNAME";
my $sth = $self->{dbh}->prepare($str) or die $self->{dbh}->errstr;
+
$sth->execute or die $sth->errstr;
- my %data = ();
+ my @users = ();
while (my $row = $sth->fetch) {
- push(@{$data{$row->[0]}}, $row->[1]) if (grep(/$row->[1]/, @pg_grants));
+ push(@users, $row->[0]);
}
- return \%data;
+ return \@users;
}
+
=head2 _get_roles
-This function implements a Oracle-native roles/users
+This function implements a Oracle-native roles
information.
Return a hash of all groups (roles) as an array of associated users.
@@ -790,43 +1065,68 @@ sub _get_roles
my($self) = @_;
# Retrieve all ROLES defined in this database
- my $str = "SELECT ROLE FROM DBA_ROLES ORDER BY ROLE";
+ my $str = "SELECT GRANTED_ROLE,GRANTEE FROM DBA_ROLE_PRIVS WHERE GRANTEE NOT IN (select distinct role from dba_roles)";
+ if (!$self->{schema}) {
+ $str .= " AND GRANTEE <> 'SYS' AND GRANTEE <> 'SYSTEM' AND GRANTEE <> 'DBSNMP'";
+ } else {
+ $str .= " AND GRANTEE = '$self->{schema}'";
+ }
my $sth = $self->{dbh}->prepare($str) or die $self->{dbh}->errstr;
$sth->execute or die $sth->errstr;
- my @roles = ();
+ my %roles = ();
while (my $row = $sth->fetch) {
- push(@roles, $row->[0]);
+ push(@{$roles{"$row->[0]"}}, $row->[1]);
}
- # Get all users associated to these roles
- my %groups = ();
- foreach my $r (@roles) {
- my $str = "SELECT GRANTEE FROM DBA_ROLE_PRIVS WHERE GRANTEE <> 'SYS' AND GRANTEE <> 'SYSTEM' AND GRANTED_ROLE='$r' AND GRANTEE IN (SELECT USERNAME FROM DBA_USERS)";
- $sth = $self->{dbh}->prepare($str) or die $self->{dbh}->errstr;
- $sth->execute or die $sth->errstr;
- my @users = ();
- while (my $row = $sth->fetch) {
- push(@users, $row->[0]);
- }
- $groups{$r} = \@users if ($#users >= 0);
+ return \%roles;
+}
+
+
+=head2 _get_all_grants
+
+This function implements a Oracle-native user privilege
+information.
+
+Return a hash of all tables grants as an array of associated users.
+
+=cut
+
+sub _get_all_grants
+{
+ my($self) = @_;
+
+ my @PG_GRANTS = ('DELETE', 'INSERT', 'SELECT', 'UPDATE');
+
+ # Retrieve all ROLES defined in this database
+ my $str = "SELECT table_name,privilege,grantee FROM DBA_TAB_PRIVS";
+ if ($self->{schema}) {
+ $str .= " WHERE GRANTEE = '$self->{schema}'";
+ } else {
+ $str .= " WHERE GRANTEE <> 'SYS' AND GRANTEE <> 'SYSTEM' AND GRANTEE <> 'DBSNMP'";
+ }
+ $str .= " ORDER BY TABLE_NAME";
+
+ my $sth = $self->{dbh}->prepare($str) or die $self->{dbh}->errstr;
+
+ $sth->execute or die $sth->errstr;
+ my %grants = ();
+ while (my $row = $sth->fetch) {
+ push(@{$grants{"$row->[0]"}{"$row->[1]"}}, $row->[2]) if (grep(/$row->[1]/, @PG_GRANTS));
}
- return \%groups;
+ return \%grants;
}
-=head2 _get_indexes TABLE
-This function implements a Oracle-native indexes
-information.
+=head2 _get_indexes TABLE
-Return an array of all indexes name which are not primary keys
-for the given table.
+This function implements a Oracle-native indexes information.
-Note: Indexes name must be created like this tablename_fieldname
-else they will not be retrieved or if tablename false in the output
-fieldname.
+Return hash of array containing all unique index and a hash of
+array of all indexes name which are not primary keys for the
+given table.
=cut
@@ -850,34 +1150,36 @@ sub _get_indexes
}
-=head2 _get_sequences TABLE
+=head2 _get_sequences
-This function implements a Oracle-native sequence
+This function implements a Oracle-native sequences
information.
Return a hash of array of sequence name with MIN_VALUE, MAX_VALUE,
INCREMENT and LAST_NUMBER for the given table.
-Not working yet.
-
=cut
sub _get_sequences
{
- my($self, $table) = @_;
+ my($self) = @_;
# Retrieve all indexes
- my $str = "SELECT SEQUENCE_NAME, MIN_VALUE, MAX_VALUE, INCREMENT_BY, LAST_NUMBER FROM DBA_SEQUENCES WHERE SEQUENCE_OWNER <> 'SYS' AND SEQUENCE_OWNER <> 'SYSTEM'";
+ my $str = "SELECT DISTINCT SEQUENCE_NAME, MIN_VALUE, MAX_VALUE, INCREMENT_BY, LAST_NUMBER, CACHE_SIZE, CYCLE_FLAG FROM DBA_SEQUENCES";
+ if (!$self->{schema}) {
+ $str .= " WHERE SEQUENCE_OWNER <> 'SYS' AND SEQUENCE_OWNER <> 'SYSTEM' AND SEQUENCE_OWNER <> 'DBSNMP'";
+ } else {
+ $str .= " WHERE SEQUENCE_OWNER = '$self->{schema}'";
+ }
my $sth = $self->{dbh}->prepare($str) or die $self->{dbh}->errstr;
$sth->execute or die $sth->errstr;
- my %data = ();
+ my @seqs = ();
while (my $row = $sth->fetch) {
- # next if ($row->[0] !~ /${table}_/);
- # push(@data, $row->[0]);
+ push(@seqs, [ @$row ]);
}
- return %data;
+ return \@seqs;
}
@@ -885,8 +1187,7 @@ sub _get_sequences
This function implements a Oracle-native views information.
-Return a hash of array of sequence name with MIN_VALUE, MAX_VALUE,
-INCREMENT and LAST_NUMBER for the given table.
+Return a hash of view name with the SQL query it is based on.
=cut
@@ -895,7 +1196,12 @@ sub _get_views
my($self) = @_;
# Retrieve all views
- my $str = "SELECT VIEW_NAME,TEXT FROM DBA_VIEWS WHERE OWNER <> 'SYS' AND OWNER <> 'SYSTEM'";
+ my $str = "SELECT VIEW_NAME,TEXT FROM DBA_VIEWS";
+ if (!$self->{schema}) {
+ $str .= " WHERE OWNER <> 'SYS' AND OWNER <> 'SYSTEM' AND OWNER <> 'DBSNMP'";
+ } else {
+ $str .= " WHERE OWNER = '$self->{schema}'";
+ }
my $sth = $self->{dbh}->prepare($str) or die $self->{dbh}->errstr;
$sth->execute or die $sth->errstr;
@@ -908,6 +1214,110 @@ sub _get_views
}
+=head2 _get_triggers
+
+This function implements a Oracle-native triggers information.
+
+Return an array of refarray of all triggers informations
+
+=cut
+
+sub _get_triggers
+{
+ my($self) = @_;
+
+ # Retrieve all indexes
+ my $str = "SELECT TRIGGER_NAME, TRIGGER_TYPE, TRIGGERING_EVENT, TABLE_NAME, TRIGGER_BODY FROM DBA_TRIGGERS WHERE STATUS='ENABLED'";
+ if (!$self->{schema}) {
+ $str .= " AND OWNER <> 'SYS' AND OWNER <> 'SYSTEM' AND OWNER <> 'DBSNMP'";
+ } else {
+ $str .= " AND OWNER = '$self->{schema}'";
+ }
+ my $sth = $self->{dbh}->prepare($str) or die $self->{dbh}->errstr;
+ $sth->execute or die $sth->errstr;
+
+ my @triggers = ();
+ while (my $row = $sth->fetch) {
+ push(@triggers, [ @$row ]);
+ }
+
+ return \@triggers;
+}
+
+
+=head2 _get_functions
+
+This function implements a Oracle-native functions information.
+
+Return a hash of all function name with their PLSQL code
+
+=cut
+
+sub _get_functions
+{
+ my($self, $type) = @_;
+
+ # Retrieve all indexes
+ my $str = "SELECT DISTINCT OBJECT_NAME,OWNER FROM DBA_OBJECTS WHERE OBJECT_TYPE='$type' AND STATUS='VALID'";
+ if (!$self->{schema}) {
+ $str .= " AND OWNER <> 'SYS' AND OWNER <> 'SYSTEM' AND OWNER <> 'DBSNMP'";
+ } else {
+ $str .= " AND OWNER = '$self->{schema}'";
+ }
+ my $sth = $self->{dbh}->prepare($str) or die $self->{dbh}->errstr;
+ $sth->execute or die $sth->errstr;
+
+ my %functions = ();
+ my @fct_done = ();
+ while (my $row = $sth->fetch) {
+ next if (grep(/^$row->[0]$/, @fct_done));
+ push(@fct_done, $row->[0]);
+ my $sql = "SELECT TEXT FROM DBA_SOURCE WHERE OWNER='$row->[1]' AND NAME='$row->[0]' ORDER BY LINE";
+ my $sth2 = $self->{dbh}->prepare($sql) or die $self->{dbh}->errstr;
+ $sth2->execute or die $sth2->errstr;
+ while (my $r = $sth2->fetch) {
+ $functions{"$row->[0]"} .= $r->[0];
+ }
+ }
+
+ return \%functions;
+}
+
+
+=head2 _table_info
+
+This function retrieve all Oracle-native tables information.
+
+Return a handle to a DB query statement
+
+=cut
+
+
+sub _table_info
+{
+ my $self = shift;
+
+ my $sql = "SELECT
+ NULL TABLE_CAT,
+ at.OWNER TABLE_SCHEM,
+ at.TABLE_NAME,
+ tc.TABLE_TYPE,
+ tc.COMMENTS REMARKS
+ from ALL_TABLES at, ALL_TAB_COMMENTS tc
+ where at.OWNER = tc.OWNER
+ and at.TABLE_NAME = tc.TABLE_NAME
+ ";
+
+ if ($self->{schema}) {
+ $sql .= " and at.OWNER='$self->{schema}'";
+ } else {
+ $sql .= "and at.OWNER <> 'SYS' and at.OWNER <> 'SYSTEM' and at.OWNER <> 'DBSNMP'";
+ }
+ $sql .= " order by tc.TABLE_TYPE, at.OWNER, at.TABLE_NAME";
+ my $sth = $self->{dbh}->prepare( $sql ) or return undef;
+ $sth->execute or return undef;
+ $sth;
+}
1;