From 65816152450e0955da098112dbde0a7092a98eeb Mon Sep 17 00:00:00 2001 From: Greg Sabino Mullane Date: Thu, 30 Jun 2011 08:12:32 -0400 Subject: [PATCH] Oracle support. Untested! --- Bucardo.pm | 62 ++++++-- MANIFEST | 3 + bucardo | 37 ++++- bucardo.schema | 23 ++- t/20-mysql.t | 18 --- t/20-oracle.t | 353 ++++++++++++++++++++++++++++++++++++++++++++ t/BucardoTesting.pm | 15 +- 7 files changed, 477 insertions(+), 34 deletions(-) create mode 100644 t/20-oracle.t diff --git a/Bucardo.pm b/Bucardo.pm index 881b7fe43..dd9ade2a5 100644 --- a/Bucardo.pm +++ b/Bucardo.pm @@ -1468,7 +1468,10 @@ sub start_controller { if ($cname) { $g->{newname}{$syncname}{$dbname} = $cname; } - elsif ($x->{dbtype} eq 'postgres' or $x->{dbtype} eq 'flatpg') { + ## Only a few use schemas: + elsif ($x->{dbtype} eq 'postgres' + or $x->{dbtype} eq 'flatpg' + or $x->{dbtype} eq 'oracle') { $g->{newname}{$syncname}{$dbname} = "$S.$T"; } else { @@ -1793,7 +1796,8 @@ sub start_kid { push @dbs_dbi => $dbname if $x->{dbtype} eq 'postgres' - or $x->{dbtype} eq 'mysql'; + or $x->{dbtype} eq 'mysql' + or $x->{dbtype} eq 'oracle'; push @dbs_connectable => $dbname if $x->{dbtype} !~ /flat/; @@ -2464,6 +2468,12 @@ sub start_kid { $x->{dbh}->do('SET TRANSACTION ISOLATION LEVEL SERIALIZABLE'); $self->glog(qq{Set db "$dbname" to serializable}, LOG_DEBUG); } + + if ($x->{dbtype} eq 'oracle') { + $x->{dbh}->do('SET TRANSACTION READ WRITE'); + $x->{dbh}->do('SET TRANSACTION ISOLATION LEVEL SERIALIZABLE'); + $self->glog(qq{Set db "$dbname" to serializable and read write}, LOG_DEBUG); + } } ## We may want to lock all the tables. Use sparingly @@ -2505,6 +2515,12 @@ sub start_kid { $self->glog("Database $dbname: Locking table $com", LOG_TERSE); $x->{dbh}->do("LOCK TABLE $com"); } + + if ($x->{dbtype} eq 'oracle') { + my $com = "$g->{safeschema}.$g->{safetable} IN EXCLUSIVE MODE"; + $self->glog("Database $dbname: Locking table $com", LOG_TERSE); + $x->{dbh}->do("LOCK TABLE $com"); + } } } } @@ -4101,6 +4117,9 @@ sub connect_database { elsif ('mysql' eq $dbtype) { $dsn = "dbi:mysql:database=$d->{dbname}"; } + elsif ('oracle' eq $dbtype) { + $dsn = "dbi:Oracle:$d->{dbname}"; + } else { die qq{Cannot handle databases of type "$dbtype"\n}; } @@ -5201,6 +5220,9 @@ sub validate_sync { ## MySQL is skipped for now, but should be added later next if $self->{sdb}{$dbname}{dbtype} =~ /mysql/o; + ## Oracle is skipped for now, but should be added later + next if $self->{sdb}{$dbname}{dbtype} =~ /oracle/o; + ## Respond to ping here and now for very impatient watchdog programs $maindbh->commit(); @@ -6920,6 +6942,12 @@ sub delete_rows { $tdbh->do("TRUNCATE TABLE $tname"); } + ## Oracle is a simple schema and table truncate + if ('oracle' eq $type) { + my $tdbh = $t->{dbh}; + $tdbh->do("TRUNCATE TABLE $tname"); + } + ## For flatfiles, write out a basic truncate statement if ($type =~ /flat/o) { printf {$t->{filehandle}} qq{TRUNCATE TABLE %S;\n\n}, @@ -6959,6 +6987,9 @@ sub delete_rows { elsif ('mysql' eq $type) { $sqltype = 'MYIN'; } + elsif ('oracle' eq $type) { + $sqltype = 'PGIN'; + } elsif ($type =~ /flatpg/o) { ## XXX Worth the trouble to allow building an ANY someday for flatpg? $sqltype = 'PGIN'; @@ -7097,6 +7128,12 @@ sub delete_rows { next; } + if ('oracle' eq $type) { + my $tdbh = $t->{dbh}; + ($count{$t} = $tdbh->do($SQL{PGIN})) =~ s/0E0/0/o; + next; + } + if ($type =~ /flatpg/o) { print {$t->{filehandle}} qq{$SQL{PGIN};\n\n}; $self->glog(qq{Appended to flatfile "$t->{filename}"}, LOG_VERBOSE); @@ -7115,12 +7152,11 @@ sub delete_rows { ## Final cleanup as needed (e.g. process async results) for my $t (@$deldb) { my $type = $t->{dbtype}; - next if 'mongo' eq $type; - next if 'mysql' eq $type; - my $tdbh = $t->{dbh}; if ('postgres' eq $type) { + my $tdbh = $t->{dbh}; + ## Wrap up all the async queries ($count{$t} = $tdbh->pg_result()) =~ s/0E0/0/o; @@ -7219,6 +7255,12 @@ sub push_rows { $tgtcmd =~ s/,$/)/o; $t->{sth} = $t->{dbh}->prepare($tgtcmd); } + elsif ('oracle' eq $type) { + my $tgtcmd = "INSERT INTO $tname VALUES ("; + $tgtcmd .= '?,' x keys %{ $goat->{columnhash} }; + $tgtcmd =~ s/,$/)/o; + $t->{sth} = $t->{dbh}->prepare($tgtcmd); + } else { die qq{No support for database type "$type" yet!}; } @@ -7279,8 +7321,8 @@ sub push_rows { } $self->{collection}->insert($object, { safe => 1 }); } - ## For MySQL, so some basic INSERTs - elsif ('mysql' eq $type) { + ## For MySQL and Oracle, do some basic INSERTs + elsif ('mysql' eq $type or 'oracle' eq $type) { my @cols = map { $_ = undef if $_ eq '\\N'; $_; } split /\t/ => $buffer; $count += $t->{sth}->execute(@cols); } @@ -7315,12 +7357,6 @@ sub push_rows { elsif ('flatsql' eq $type) { print {$t->{filehandle}} ";\n\n"; } - elsif ('mongo' eq $type) { - ## Nothing special needed - } - elsif ('mysql' eq $type) { - ## Nothing special needed - } } return $count; diff --git a/MANIFEST b/MANIFEST index 98f8705ee..5e1246032 100644 --- a/MANIFEST +++ b/MANIFEST @@ -33,6 +33,9 @@ t/02-bctl-db.t t/02-bctl-dbg.t t/09-uniqueconstraint.t t/15-star.t +t/20-mongo.t +t/20-mysql.t +t/20-oracle.t t/98-cleanup.t t/99-signature.t t/BucardoTesting.pm diff --git a/bucardo b/bucardo index 40bc853d7..2ebbd69e8 100755 --- a/bucardo +++ b/bucardo @@ -805,6 +805,7 @@ sub add_database { $vals->{dbtype} =~ s/postgres.*/postgres/io; $vals->{dbtype} =~ s/mongo.*/mongo/io; $vals->{dbtype} =~ s/mysql.*/mysql/io; + $vals->{dbtype} =~ s/oracle.*/oracle/io; ## Attempt to insert this into the database $SQL = "INSERT INTO bucardo.db ($cols) VALUES ($phs)"; @@ -831,7 +832,7 @@ sub add_database { last TESTCONN if 'flatfile' eq $vals->{dbtype}; ## Must have a valid type - if ($vals->{dbtype} !~ /^(?:postgres|mongo|mysql)$/) { + if ($vals->{dbtype} !~ /^(?:postgres|mongo|mysql|oracle)$/) { die qq{Unknown database type: $vals->{dbtype}\n}; } @@ -949,6 +950,33 @@ sub add_database { } ## end mysql + if ('oracle' eq $vals->{dbtype}) { + + my ($type,$dsn,$user,$pass) = split /\n/ => $dbconn; + + my $found = 0; + eval { + require DBD::Oracle; + $found = 1; + }; + if (!$found) { + die "Cannot add unless the DBD::Oracle module is available\n"; + } + + my $testdbh; + $found = 0; + eval { + $testdbh = DBI->connect($dsn, $user, $pass, {AutoCommit=>0,RaiseError=>1,PrintError=>0}); + $found = 1; + }; + if (! $found) { + die "Oracle connection test failed. You can force add it with the --force argument. Error was: $@\n\n"; + } + + $testdbh->disconnect(); + + } ## end oracle + } ## end of TESTCONN ## If we got a group, process that as well @@ -1351,6 +1379,12 @@ sub list_databases { $showhost, $showport; } + if ($dbtype eq 'oracle') { + printf "Conn: sqlplus %s%s", + $info->{dbuser}, + $showhost ? qq{\@$showhost} : ''; + } + print "\n"; if ($VERBOSE) { @@ -4475,6 +4509,7 @@ sub process_args { $arg{type} =~ s/postgres.*/postgres/io; $arg{type} =~ s/mongo.*/mongo/io; $arg{type} =~ s/mysql.*/mysql/io; + $arg{type} =~ s/oracle.*/oracle/io; } return \%arg; diff --git a/bucardo.schema b/bucardo.schema index 26d1966ce..021f42279 100644 --- a/bucardo.schema +++ b/bucardo.schema @@ -609,8 +609,9 @@ AS $bc$ ## Given the name of a db, return the type, plus type-specific connection information ## Postgres: a connection string, username, password, and attribs -## Mongo: foo: bar connection information, one per line +## Mongo: "foo: bar" style connection information, one per line ## MySQL: a connection string, username, and password +## Oracle: a connection string, username, and password use strict; use warnings; @@ -690,6 +691,23 @@ if ($dbtype eq 'mysql') { } ## end mysql +if ($dbtype eq 'oracle') { + + ## We should loosen this up somewhere + length $db{name} or elog(ERROR, qq{Database name is mandatory\n}); + length $db{user} or elog(ERROR, qq{Database username is mandatory\n}); + + ## TODO: Support SID, other forms + my $connstring = "dbi:Oracle:$db{name}"; + $db{host} ||= ''; $db{port} ||= ''; $db{pass} ||= ''; + length $db{host} and $connstring .= ";host=$db{host}"; + length $db{port} and $connstring .= ";port=$db{port}"; + length $db{conn} and $connstring .= ";$db{conn}"; + + return "$dbtype\n$connstring\n$db{user}\n$db{pass}"; + +} ## end oracle + if ($dbtype eq 'mongo') { my $connstring = "$dbtype\n"; for my $name (qw/ host port user pass /) { @@ -1192,6 +1210,9 @@ for my $dbname (sort { ($db{$b}{role} eq 'source') <=> ($db{$a}{role} eq 'source ## Skip if this is mysql next if $db{$dbname}{dbtype} eq 'mysql'; + ## Skip if this is oracle + next if $db{$dbname}{dbtype} eq 'oracle'; + ## Figure out how to connect to this database my $rv = spi_exec_query("SELECT bucardo.db_getconn('$dbname') AS conn"); $rv->{processed} or elog(ERROR, qq{Error: Could not find a database named "$dbname"\n}); diff --git a/t/20-mysql.t b/t/20-mysql.t index d89e3b7ee..5480c1b78 100644 --- a/t/20-mysql.t +++ b/t/20-mysql.t @@ -349,22 +349,4 @@ for my $table (keys %tabletype) { is ($count, 3, $t); } -__END__ -for my $table (keys %tabletype) { - $sth{truncate}{$table}{A}->execute(); -} -$dbhA->commit(); -$bct->ctl('bucardo kick mongo 0'); - -for my $table (keys %tabletype) { - $t = "Mongo collection $table has correct number of rows after trunacte"; - my $col = $db->get_collection($table); - my @rows = $col->find->all; - my $count = @rows; - is ($count, 0, $t); -} - -pass('Done with mongo testing'); - exit; - diff --git a/t/20-oracle.t b/t/20-oracle.t new file mode 100644 index 000000000..6afa9fbb1 --- /dev/null +++ b/t/20-oracle.t @@ -0,0 +1,353 @@ +#!/usr/bin/env perl +# -*-mode:cperl; indent-tabs-mode: nil-*- + +## Test using Oracle as a database target + +use 5.008003; +use strict; +use warnings; +use Data::Dumper; +use lib 't','.'; +use DBD::Pg; +use Test::More; +use MIME::Base64; + +use vars qw/ $bct $dbhX $dbhA $dbhB $dbhC $dbhD $res $command $t %pkey $SQL %sth %sql/; + +## Must have the DBD::Oracle module +my $evalok = 0; +eval { + require DBD::Oracle; + $evalok = 1; +}; +if (!$evalok) { + plan (skip_all => 'Cannot test Oracle unless the Perl module DBD::Oracle is installed'); +} + +## Oracle must be up and running +$evalok = 0; +my $dbh; +my $dbuser = 'root'; +eval { + $dbh = DBI->connect('dbi:Oracle:test', $dbuser, '', + {AutoCommit=>1, PrintError=>0, RaiseError=>1}); + $evalok = 1; +}; +if (!$evalok) { + plan (skip_all => "Cannot test Oracle as we cannot connect to a running Oracle database: $@"); +} + +use BucardoTesting; + +## For now, remove the bytea table type as we don't have full MySQL support yet +delete $tabletype{bucardo_test8}; + +my $numtabletypes = keys %tabletype; +plan tests => 119; + +## Drop the test database if it exists +my $dbname = 'bucardo_test'; +eval { + $dbh->do("DROP DATABASE $dbname"); +}; +## Create the test database +$dbh->do("CREATE DATABASE $dbname"); + +## Reconnect to the new database +$dbh = DBI->connect("dbi:Oracle:$dbname", $dbuser, '', + {AutoCommit=>1, PrintError=>0, RaiseError=>1}); + +## Create one table for each table type +for my $table (sort keys %tabletype) { + + my $pkeyname = $table =~ /test5/ ? q{`id space`} : 'id'; + my $pkindex = $table =~ /test2/ ? '' : 'PRIMARY KEY'; + $SQL = qq{ + CREATE TABLE $table ( + $pkeyname $tabletypemysql{$table} NOT NULL $pkindex}; + $SQL .= $table =~ /X/ ? "\n)" : qq{, + data1 NVARCHAR2(100) NULL, + inty SMALLINT NULL, + bite1 BLOB NULL, + bite2 BLOB NULL, + email NVARCHAR2(100) NULL UNIQUE + ) + }; + + $dbh->do($SQL); + + if ($table =~ /test2/) { + $dbh->do("ALTER TABLE $table ADD CONSTRAINT multipk PRIMARY KEY ($pkeyname,data1)"); + } + +} + +$bct = BucardoTesting->new() or BAIL_OUT "Creation of BucardoTesting object failed\n"; +$location = 'oracle'; + +pass("*** Beginning mysql tests"); + +END { + $bct and $bct->stop_bucardo($dbhX); + $dbhX and $dbhX->disconnect(); + $dbhA and $dbhA->disconnect(); + $dbhB and $dbhB->disconnect(); + $dbhC and $dbhC->disconnect(); +} + +## Get Postgres database A and B and C created +$dbhA = $bct->repopulate_cluster('A'); +$dbhB = $bct->repopulate_cluster('B'); +$dbhC = $bct->repopulate_cluster('C'); + +## Create a bucardo database, and install Bucardo into it +$dbhX = $bct->setup_bucardo('A'); + +## Tell Bucardo about these databases + +## Three Postgres databases will be source, source, and target +for my $name (qw/ A B C /) { + $t = "Adding database from cluster $name works"; + my ($dbuser,$dbport,$dbhost) = $bct->add_db_args($name); + $command = "bucardo add db $name dbname=bucardo_test user=$dbuser port=$dbport host=$dbhost"; + $res = $bct->ctl($command); + like ($res, qr/Added database "$name"/, $t); +} + +$t = 'Adding oracle database Q works'; +$command = +"bucardo add db Q dbname=$dbname type=oracle dbuser=$dbuser"; +$res = $bct->ctl($command); +like ($res, qr/Added database "Q"/, $t); + +## Teach Bucardo about all pushable tables, adding them to a new herd named "therd" +$t = q{Adding all tables on the master works}; +$command = +"bucardo add tables all db=A herd=therd pkonly"; +$res = $bct->ctl($command); +like ($res, qr/Creating herd: therd.*New tables added: \d/s, $t); + +## Add all sequences, and add them to the newly created herd +$t = q{Adding all sequences on the master works}; +$command = +"bucardo add sequences all db=A herd=therd"; +$res = $bct->ctl($command); +like ($res, qr/New sequences added: \d/, $t); + +## Create a new database group +$t = q{Created a new database group}; +$command = +"bucardo add dbgroup qx A:source B:source C Q"; +$res = $bct->ctl($command); +like ($res, qr/Created database group "qx"/, $t); + +## Create a new sync +$t = q{Created a new sync}; +$command = +"bucardo add sync oracle herd=therd dbs=qx ping=false"; +$res = $bct->ctl($command); +like ($res, qr/Added sync "oracle"/, $t); + +## Create a second sync, solely for multi-sync interaction issues +$bct->ctl('bucardo add dbgroup t1 A:source B C'); +$bct->ctl('bucardo add sync tsync1 herd=therd dbs=t1 ping=false status=inactive'); + +## Start up Bucardo with these new syncs +$bct->restart_bucardo($dbhX); + +## Get the statement handles ready for each table type +for my $table (sort keys %tabletype) { + + $pkey{$table} = $table =~ /test5/ ? q{"id space"} : 'id'; + + ## INSERT + for my $x (1..6) { + $SQL = $table =~ /X/ + ? "INSERT INTO $table($pkey{$table}) VALUES (?)" + : "INSERT INTO $table($pkey{$table},data1,inty) VALUES (?,'foo',$x)"; + $sth{insert}{$x}{$table}{A} = $dbhA->prepare($SQL); + if ('BYTEA' eq $tabletype{$table}) { + $sth{insert}{$x}{$table}{A}->bind_param(1, undef, {pg_type => PG_BYTEA}); + } + } + + ## SELECT + $sql{select}{$table} = "SELECT inty FROM $table ORDER BY $pkey{$table}"; + $table =~ /X/ and $sql{select}{$table} =~ s/inty/$pkey{$table}/; + + ## DELETE ALL + $SQL = "DELETE FROM $table"; + $sth{deleteall}{$table}{A} = $dbhA->prepare($SQL); + + ## DELETE ONE + $SQL = "DELETE FROM $table WHERE inty = ?"; + $sth{deleteone}{$table}{A} = $dbhA->prepare($SQL); + + ## TRUNCATE + $SQL = "TRUNCATE TABLE $table"; + $sth{truncate}{$table}{A} = $dbhA->prepare($SQL); + ## UPDATE + $SQL = "UPDATE $table SET inty = ?"; + $sth{update}{$table}{A} = $dbhA->prepare($SQL); +} + +## Add one row per table type to A +for my $table (keys %tabletype) { + my $type = $tabletype{$table}; + my $val1 = $val{$type}{1}; + $sth{insert}{1}{$table}{A}->execute($val1); +} + +## Before the commit on A, B and C should be empty +for my $table (sort keys %tabletype) { + my $type = $tabletype{$table}; + $t = qq{B has not received rows for table $table before A commits}; + $res = []; + bc_deeply($res, $dbhB, $sql{select}{$table}, $t); + bc_deeply($res, $dbhC, $sql{select}{$table}, $t); +} + +## Commit, then kick off the sync +$dbhA->commit(); +$bct->ctl('bucardo kick oracle 0'); +$bct->ctl('bucardo kick oracle 0'); + +## Check B and C for the new rows +for my $table (sort keys %tabletype) { + + my $type = $tabletype{$table}; + $t = qq{Row with pkey of type $type gets copied to B}; + + $res = [[1]]; + bc_deeply($res, $dbhB, $sql{select}{$table}, $t); + bc_deeply($res, $dbhC, $sql{select}{$table}, $t); +} + +## Check that Oracle has the new rows +for my $table (sort keys %tabletype) { + $t = "Oracle table $table has correct number of rows after insert"; + $SQL = "SELECT * FROM $table"; + my $sth = $dbh->prepare($SQL); + my $count = $sth->execute(); + is ($count, 1, $t); + + $t = "Oracle table $table has correct entries"; + my $info = $sth->fetchall_arrayref({})->[0]; + my $type = $tabletype{$table}; + my $id = $val{$type}{1}; + my $pkeyname = $table =~ /test5/ ? 'id space' : 'id'; + + ## For now, binary is stored in escaped form, so we skip this one + next if $table =~ /test8/; + + ## Datetime has no time zone thingy at the end + $tabletypeoracle{$table} =~ /DATETIME/ and $id =~ s/\+.*//; + + is_deeply( + $info, + { + $pkeyname => $id, + inty => 1, + email => undef, + bite1 => undef, + bite2 => undef, + data1 => 'foo', + }, + + $t); +} + +## Update each row +for my $table (keys %tabletype) { + $sth{update}{$table}{A}->execute(42); +} +$dbhA->commit(); +$bct->ctl('bucardo kick oracle 0'); + +for my $table (keys %tabletype) { + $t = "Oracle table $table has correct number of rows after update"; + $SQL = "SELECT * FROM $table"; + my $sth = $dbh->prepare($SQL); + my $count = $sth->execute(); + is ($count, 1, $t); + + $t = "Oracle table $table has updated value"; + my $info = $sth->fetchall_arrayref({})->[0]; + is ($info->{inty}, 42, $t); +} + +## Delete each row +for my $table (keys %tabletype) { + $sth{deleteall}{$table}{A}->execute(); +} +$dbhA->commit(); +$bct->ctl('bucardo kick oracle 0'); + +for my $table (keys %tabletype) { + $t = "Oracle table $table has correct number of rows after delete"; + $SQL = "SELECT * FROM $table"; + my $sth = $dbh->prepare($SQL); + (my $count = $sth->execute()) =~ s/0E0/0/; + $sth->finish(); + is ($count, 0, $t); +} + +## Insert two rows, then delete one of them +## Add one row per table type to A +for my $table (keys %tabletype) { + my $type = $tabletype{$table}; + my $val1 = $val{$type}{1}; + $sth{insert}{1}{$table}{A}->execute($val1); + my $val2 = $val{$type}{2}; + $sth{insert}{2}{$table}{A}->execute($val2); +} +$dbhA->commit(); +$bct->ctl('bucardo kick oracle 0'); + +for my $table (keys %tabletype) { + $t = "Oracle table $table has correct number of rows after double insert"; + $SQL = "SELECT * FROM $table"; + my $sth = $dbh->prepare($SQL); + my $count = $sth->execute(); + $sth->finish(); + is ($count, 2, $t); +} + +## Delete one of the rows +for my $table (keys %tabletype) { + $sth{deleteone}{$table}{A}->execute(2); ## inty = 2 +} +$dbhA->commit(); +$bct->ctl('bucardo kick oracle 0'); + +for my $table (keys %tabletype) { + $t = "Oracle table $table has correct number of rows after single deletion"; + $SQL = "SELECT * FROM $table"; + my $sth = $dbh->prepare($SQL); + my $count = $sth->execute(); + $sth->finish(); + is ($count, 1, $t); +} + +## Insert two more rows, then truncate +for my $table (keys %tabletype) { + my $type = $tabletype{$table}; + my $val3 = $val{$type}{3}; + $sth{insert}{3}{$table}{A}->execute($val3); + my $val4 = $val{$type}{4}; + $sth{insert}{4}{$table}{A}->execute($val4); +} +$dbhA->commit(); +$bct->ctl('bucardo kick oracle 0'); + +for my $table (keys %tabletype) { + $t = "Oracle table $table has correct number of rows after more inserts"; + $SQL = "SELECT * FROM $table"; + my $sth = $dbh->prepare($SQL); + my $count = $sth->execute(); + $sth->finish(); + is ($count, 3, $t); +} + +exit; + diff --git a/t/BucardoTesting.pm b/t/BucardoTesting.pm index 052e11797..5aca05f24 100644 --- a/t/BucardoTesting.pm +++ b/t/BucardoTesting.pm @@ -18,7 +18,7 @@ use vars qw/$SQL $sth $count $COM %dbh/; my $DEBUG = $ENV{BUCARDO_DEBUG} || 0; use base 'Exporter'; -our @EXPORT = qw/%tabletype %tabletypemysql %sequences %val compare_tables bc_deeply clear_notices +our @EXPORT = qw/%tabletype %tabletypemysql %tabletypeoracle %sequences %val compare_tables bc_deeply clear_notices wait_for_notice $location is_deeply like pass is isa_ok ok $oldherd_msg $newherd_msg $addtable_msg $deltable_msg $nomatch_msg/; @@ -84,6 +84,19 @@ our %tabletypemysql = 'bucardo_test10' => 'DATETIME', ); +our %tabletypeoracle = + ( + 'bucardo_test1' => 'SMALLINT', + 'bucardo_test2' => 'INT', + 'bucardo_test3' => 'BIGINT', + 'bucardo_test4' => 'NVARCHAR2(1000)', + 'bucardo_test5' => 'DATE', + 'bucardo_test6' => 'TIMESTAMP', + 'bucardo_test7' => 'NUMERIC(5,1)', + 'bucardo_test8' => 'BLOB', + 'bucardo_test9' => 'INTEGER', + 'bucardo_test10' => 'TIMESTAMP WITH TIME ZONE', + ); our @tables2empty = (qw/droptest/); -- 2.39.5