Looks like Oracle has finally come around and made it easier to incorporate the DBI module into the Oracle HTTP Server. The 10gR2 HTTP Server Administrators guide also has a laundry list of other modules that are enabled by default or easily turned on.
Here is the mod_perl section of the 10gR2 HTTP Server Admininistrators Guide: click here
Yes, I can't believe it, but Oracle made something easy for once. Uncomment a line in the http.conf, restart the httpd server, customize your perl script, and you should be mod_perling with DBI.
A couple of notes:
Shebang #!:
To keep things simple it is best to use the Perl in the Oracle Home the http server is running out of, not the generic /usr/bin/perl that is available on most machines.
So yes your Shebang will look ugly, but it will cut down on confusion. Mine looks something like this:
#!/u01/app/oracle/product/10.2.0.3/perl/bin/perl -w
Just remember that you'll have to modify scripts before they are run. If you have any weirdness (like I did) it may be because the scripts had the default #!/usr/bin/perl which was missing DBI.
Port:
To find the port your server is running on, locate the "Port" configuration item in your $ORACLE_HOME/Apache/Apache/conf/httpd.conf file.
http://machinename:port/cgi-bin/test.pl
Here are instructions for getting Perl to work with Oracle on a PC/Windows client:
1) Download ActiveState Perl
http://www.activestate.com/store/activeperl/download
2) Run the Perl Package Manager
Two packages must be installed for Perl to talk to Oracle. The DBI (Database Interface) and the DBD (Database Driver).
ppm> install DBI
ppm> install ftp://ftp.esoftmatic.com/outgoing/DBI/5.8.3/DBD-Oracle.ppd
3) Install the Oracle Client (if needed)
If you have come this far you probably already have the Oracle client installed. If not, fire up the installer on the Oracle Install Media and install at least the Client.
4) Set up TNSNAMES.ORA
Include servers that you would like to connect to.
5) Try some examples
Example 1: Run a Simple SQL Command
This script runs a simple SQL command. If an Oracle error is thrown, it will be reported to the user.
#!/bin/perl
use strict;
use DBI;my $dbh = DBI->connect( 'dbi:Oracle:[enter_sidname_here]',
'[enter_oracle_username_here]',
'[enter_password]',
{
RaiseError => 1,
AutoCommit => 0
}
) || die "Database connection not made: $DBI::errstr";# Text of SQL Statement
my $sql = qq{ DROP TABLE EMPLOYEES };
# Run SQL Statement
$dbh->do( $sql );
# Disconnect
$dbh->disconnect() or warn "DB disconnection failed: $DBI::errstrn";
Example 2: Run a Query and Print Results
This script runs a query and scans through the results.
To add more fields to the query and output make sure to update the bind_columns function with the new fields.
#!/bin/perl
use strict;
use DBI;# Run a SELECT
my $dbh = DBI->connect( 'dbi:Oracle:[enter_sidname_here]',
'[enter_oracle_username_here]',
'[enter_password]',
{
RaiseError => 1,
AutoCommit => 0
}
) || die "Database connection not made: $DBI::errstr";
my $sql = qq{ SELECT TABLE_NAME FROM USER_TABLES };
# Prepare and execute SELECT
my $sth = $dbh->prepare($sql);
$sth->execute();
# Declare and Bind Column(s)
my($table_name);
$sth->bind_columns(undef, $table_name);
# Fetch rows from DB
print "List of tables:nn";
while( $sth->fetch() ) {
print "Object: $table_name";
}
# Close cursor
$sth->finish();
$dbh->disconnect() or warn "DB disconnection failed: $DBI::errstrn";
A collection of handy Perl scripts for use with Oracle.
df -k . output:
Filesystem kbytes used avail capacity Mounted on
nas03:/vol/vol38/db_data 943718400 759145092 184573308 81% /mounts/db_data
To extract the Nas Host Name and Volume Name for use in a shell script:
NASHOST=`df -k . | perl -ne '/^(.*):/ && print "$1"'`
VOLUME=`df -k . | perl -ne '/\/vol\/([a-z]*[0-9]*)/ && print "$1"'`
Description:
This script continuously watches and interprets the contents of the v$Session_LongOps view.
One of the redeeming qualities of the Java Oracle Enterprise Manager is the progress bar that comes up when you are viewing the long operations of a session. I wanted this functionality but didn't want to wake up the big lug to get this info (it takes a long time to start up and navigate to the screen to see the single long operations progress bar). So I decided to write a short script to emulate that functionality but take it one step further and show me info about _all_ the longops currently running on an instance.
This can be useful when you are performing long operations on your database instance like:
o Exporting
o Rebuilding indexes
o Long running updates
o Long running queries
From Oracle MetaLink Note 180924.1:
This view displays the status of various operations that run for longer than 6 seconds (in absolute time). These operations currently include many backup and recovery functions, statistics gathering, and query execution, and more operations are added for every Oracle release.
To monitor query execution progress, you must be using the cost-based optimizer and you must:
o Set the TIMED_STATISTICS or SQL_TRACE parameter to TRUE
o Gather statistics for your objects with the ANALYZE statement or the DBMS_STATS package
Screen shot:
Running the Script:
perl WatchLongops.pl username/password@tnsname
Hit Ctrl-c to stop the script.
Source Code:
longops.pl:
To Do:
o Secure the script, username and password on the command line is not so great on Unix (visible with ps -ef).
o System "cls" only works in DOS-land. Investigate eliminating this system call and using Curses for prettier output.
o Add ability to configure refresh time.
o Add a friendlier way to exit besides Ctrl-c.(May require ReadTerm CPAN package which is not included with Oracle's Perl by default)
# David Mann
# http://ba6.us
use strict;
use DBI;
# WatchInstanceLongops.pl
# This program runs continuously to show current Long Operations on
# an Oracle Instance.
die "\nWatchInstanceLongops.pl\n\n" .
"This procedure watches long operations on an instance.\n\n" .
"syntax: perl $0 [SCHEMA_NAME]/[SCHEMA_PASSWORD]@[TNSNAME]\n"
if @ARGV < 0;
# Get command line arguments
my ( $connect_string ) = @ARGV;
# Connect to DB
print "Connecting to DB...\n";
my $dbh = getDBConnection( $connect_string );
### SQL Query that drives this procedure ###
my $sql = qq{ select ROUND(sofar/(totalwork+1)*100,2) as pct,
elapsed_seconds,
time_remaining,
v\$session_longops.message
from v\$session_longops
where sofar<>totalwork
order by target, sid
};
### Main Program : Begin ###
my($percent, $secselap, $secsleft, $message);
my ($count);
my $sth = $dbh->prepare($sql);
while (1) {
writeHeader($connect_string);
# Prepare and execute SELECT
$sth->execute();
# Declare and Bind Columns
$sth->bind_columns(undef, \$percent, \$secselap, \$secsleft, \$message);
# Fetch rows from DB
while( $sth->fetch() ) {
writeOutputBlock($percent, $message, $secselap, $secsleft);
}
sleep(3);
}
print "\ndone\n";
$sth->finish(); # Close cursor
$dbh->disconnect() or warn "DB disconnection failed: $DBI::errstr\n";
close(OUT);
### Main Program : End ###
# Function: getDBConnection
# Parameters: $connString - connection string in format user/password@tnsname
sub getDBConnection {
my ($connectstring) = @_;
my $slashpos = index($connectstring,'/');
my $atpos = index($connectstring,'@');
die "missing /" if ($slashpos == -1);
die "missing @" if ($atpos == -1);
my $username = substr($connectstring, 0, $slashpos);
my $password = substr($connectstring, $slashpos+1, $atpos - $slashpos - 1);
my $tnsname = substr($connectstring, $atpos + 1);
return DBI->connect( "dbi:Oracle:".$tnsname,
$username,
$password,
{
RaiseError => 1,
AutoCommit => 0
}
) || die "Database connection not made: $DBI::errstr";
};
# Function: writeHeader
# Parameters: $connString - connection string in format user/password@tnsname
sub writeHeader {
my ($connectstring) = @_;
my $atpos = index($connectstring,'@');
die "missing @" if ($atpos == -1);
system "cls";
print "Monitoring Instance: " . substr($connectstring, $atpos + 1) . "\n\n";
};
# Function: writeOutputBlock
# Parameters: $percent - percent done (0 - 100)
# $message - Text message from v$session_longops
# $secselap - Seconds elapsed from v$session_longops
# $secsleft - Estimated seconds left from v$session_longops
sub writeOutputBlock {
my ($percent, $message, $secselap, $secsleft) = @_;
print substr($message,0,79) . "\n";
print "Percent : $percent ";
print "Minutes elapsed : " . int($secselap/60) . ":" . sprintf("%02s", $secselap % 60) . " ";
print "Est. Minutes left : " . int($secsleft/60) . ":" . sprintf("%02s", $secsleft % 60) . "\n";
&writeProgressBar($percent,80);
print "\n";
};
# Function: writeProgressBar
# Parameters: $perc - percent done (0 - 100)
# $width - Total width of the Progress Bar
sub writeProgressBar {
my ($perc, $width) = @_;
my $spaces = int($perc / 100 * ($width-2));
print "|";
for ($count = 1; $count <= ($width-2); $count++) {
if ($count < $spaces) {
print "X";
} else {
print "=";
}
};
print "|";
};
use strict;
use FileHandle;
use DBI;
# David Mann
# http://ba6.us
# read the compulsory arguments
die "\nOracle DB Connection Monitor\n\nsyntax: perl $0 user password instance\n" if @ARGV < 3;
my ( $user, $pass, $instance) = @ARGV;
my $filename=$ARGV[3];
my $output_to_file = 0;
my $OUT;
my $header = "TIMESTAMP,USER,MACHINE,SUM_PGAMEM,AVG_PGAMEM,COUNT\n";
# If output to file requested
if (@ARGV==4) {
print "Output to file " . $filename;
$output_to_file = 1;
open(OUT,">>$filename") or die "Cannot open $filename for writing.";
# $OUT->autoflush(0);
print OUT $header;
};
# Run a SELECT
my $dbh = DBI->connect( 'dbi:Oracle:' . $instance,
$user,
$pass,
{
RaiseError => 1,
AutoCommit => 0
}
) || die "Database connection not made: $DBI::errstr";
my $sql = qq{
SELECT TO_CHAR(sysdate, 'MM/DD/YYYY HH24:MI:SS') || ',' ||
username || ',' ||
UPPER(machine) || ',' ||
TRIM(TO_CHAR(SUM(value), '999999999999')) || ',' ||
TRIM(TO_CHAR(AVG(value), '999999999999')) || ',' ||
COUNT(*) as OutputText,
COUNT(*) as Count
FROM v\$statname n,
v\$sesstat s,
v\$session ss
WHERE n.STATISTIC# = s.STATISTIC#
AND s.sid = ss.sid
AND n.name like 'session pga memory'
GROUP BY USERNAME, MACHINE
ORDER BY USERNAME, MACHINE
};
# Prepare and execute SELECT
my $sth = $dbh->prepare($sql);
do {
$sth->execute();
my($OutputText,$Count); # Declare columns
$sth->bind_columns(undef, \$OutputText, \$Count);
print "\n" . $header;
while( $sth->fetch() ) {
print "$OutputText\n";
# Beep if count > 20
if ($Count > 20) {
print chr(07);
};
# Output to file if required
if ($output_to_file = 1) {
print OUT "$OutputText\n";
};
}
sleep(20);
} while 1;
$sth->finish(); # Close cursor
$dbh->disconnect() or warn "DB disconnection failed: $DBI::errstr\n";
close(OUT);
use strict; use DBI; # SimpleQuery.pl # David Mann # http://ba6.us # Runs and outputs a simple query from an Oracle DB die "\n$0\n\n" . "This procedure shows how to do a simple query and output the results to a file.\n\n" . "syntax: perl $0 [SCHEMA_NAME] [SCHEMA_PASSWORD] [TNSNAME] [OUTPUT_FILENAME]\n" if @ARGV < 3; # Get command line arguments my ( $schema_name, $schema_password, $tnsname, $output_filename) = @ARGV; # Connect to DB print "Connecting to DB...\n"; my $dbh = DBI->connect( "dbi:Oracle:".$tnsname, $schema_name, $schema_password, { RaiseError => 1, AutoCommit => 0 } ) || die "Database connection not made: $DBI::errstr"; # Open output file open(OUT,">$output_filename") || die "cannot create $output_filename $!"; print OUT "-- File generated for $schema_name \@ $tnsname on " . localtime() . "\n\n"; print OUT "SET SERVEROUTPUT ON;\n"; ### SQL Query that drives this procedure ### my $sql = qq{ select table_name, num_rows FROM user_tables }; ### Main ### # Prepare and execute SELECT print "Executing query...\n"; my $sth = $dbh->prepare($sql); $sth->execute(); # Declare and Bind Columns my($table_name,$num_rows); $sth->bind_columns(undef, \$table_name, \$num_rows); # Fetch rows from DB and process them print "Processing."; my $out_line; while( $sth->fetch() ) { # Output status to screen print "."; # Output data to file print OUT $table_name . " " . $num_rows . "\n"; } # Output status to screen print "\ndone\n"; $sth->finish(); # Close cursor $dbh->disconnect() or warn "DB disconnection failed: $DBI::errstr\n"; close(OUT);