There is no such (non-commercial) tool to my knowledge. One can create fancy ERDs with MS-Access or Silverrun (don't ask for details, though =).
In the hopes it may help, I recently wrote myself a little tool that generates Docbook XML tables, with a little hacking and a little wrapping (ok, those last two "little"s are understatements) you could build this into a module that could prove very useful. It doesn't do constraints (yet), or map out procedures and the like. I have JDeveloper, a Java IDE that lets me browse the DB, and I haven't yet needed to add that functionality.
This is pre-alpha code. Written after 10 minutes of thought. Is inefficient, and is certainly incomplete on the data types list. No warranty. Use at your own risk. I take no responsibility for melted CPUs or other damages to you, your love life, your career, etc. No license, though if I work it up into a module.
update: I left out the bit of code where I got the table name -- I just nabbed it from the command line. To get a list of table names in Oracle, use:
SELECT table_name FROM user_tables
And get a list of constraints with
SELECT column_name from ALL_CONS_COLUMNS WHERE owner= ? and table_name
+ = ?
First placeholder should be uc $username and second should be uc $table_name ... one place where Oracle *IS* case-sensitive. Also note that the view user_constraints is more likely to be truly helpful here.
I'm continuing to work on it, at least in terms of generating XML, but there's no reason it couldn't be hacked to produce data structures and subclassed to generate whatever from those structures.
#!/usr/bin/perl -w
# utility to generate Docbook tables from
# Oracle database
# first rev, Oct. 2001
use strict;
use DBI;
# set up translation table to go from oracle numeric codes
# to nice user-readable strings.
# yes, DBD::Oracle qw(:ora_types); does the reverse, so I
# should probably have used that. Next rev., 'k?
my %trans;
my @keys = (1..12);
my @values = qw(SQL_CHAR SQL_NUMERIC NUMBER SQL_INTEGER SQL_SMALLINT S
+QL_FLOAT
SQL_REAL SQL_DOUBLE DATE SQL_TIME SQL_TIMESTAMP VARCHAR2);
@trans{@keys} = @values;
$trans{-9112} = "CLOB";
# fields for which to ignore the precision
my %no_pres = ( DATE=>1, CLOB=>1 );
#foreach ( sort keys %trans ) {
# print "$_ => $trans{$_}\n";
#}
# obviously, the next two lines need a-hackin'
$ENV{'ORACLE_HOME'} = "/usr/oracle";
my $db = DBI->connect('dbi:Oracle:host="oracle.host.com";sid="SID"',
'username',
'password',
{RaiseError=>1,
AutoCommit=>0});
my $sth = $db->prepare("SELECT * FROM $table_name")
or die "Can't prepare statement: $db->errstr\n";
$sth->execute();
open OUTPUT, ">output.xml" or die "Can't open output.xml for write: $!
+\n";
select OUTPUT;
print <<END_OF_HEADER;
<table>
<title>Table Description for $table_name</title>
<tgroup cols="2">
<thead>
<row>
<entry align="center"><emphasis role="bold">Column Name</emphasis>
+</entry>
<entry align="center"><emphasis role="bold">Column Type</emphasis></e
+ntry>
</row>
</thead>
<tbody>
END_OF_HEADER
my $i = $sth->{NUM_OF_FIELDS};
for my $field ( 0 .. $i-1 ) {
print " <row>\n";
print " <entry align=\"center\">$sth->{NAME_lc}->[$field]</entry
+>\n";
my $ft = $sth->{TYPE}->[$field];
if ( exists($trans{$ft}) ) {
print " <entry align=\"center\">$trans{$ft}";
print "($sth->{PRECISION}->[$field])" unless $no_pres{$trans{
+$ft}};
print "</entry>\n";
} else {
print "Unknown type $ft</entry>\n";
}
print " </row>\n";
}
print " </tgroup>\n </tbody>\n</table>\n";
$sth->finish();
close OUTPUT;
select STDIN;
$db->disconnect;
HTH, it's just a start.
perl -e 'print "How sweet does a rose smell? "; chomp ($n = <STDIN>);
+$rose = "smells sweet to degree $n"; *other_name = *rose; print "$oth
+er_name\n"'