#!/usr/local/bin/oraperl
'di';
'ig00';
#
# sql
#
# Script to run an Oracle statement from the command line.
# Written in response to <nirad.690285085@newdelphi> in alt.sources.wanted.
#
# Parameters (* = mandatory)
#
#	-#debug		  debugging control string (must be first argument)
#	-b base		  database to use (default $ENV{'ORACLE_SID'})
#	-c cache	  SQL fetch cache size
#	-d delim	  specifies the field delimiter (default TAB)
#	-f		  formatted output, similar to sqlplus
#	-h		  add headers, no formatting
#	-l page_len	  lines per page, only used by -f (default 60)
#	-n string	  replace NULL fields by string
#	name/pass	* Oracle username and password
#	stmt		  Oracle statement to be executed
#			  read from stdin if not given on command line
#
# Author:	Kevin Stock
# Date:		18th November 1991
# Last change:	9th June 1993
#
eval 'use Oraperl; 1' || die $@ if $] >= 5;

$ora_debug = shift if $ARGV[0] =~ /^-#/;

$USAGE = <<;
[-bbase] [-ccache] [-ddelim] [-f|-h] [-lpage_len] [-nstring] name/pass [stmt]

require 'getopts.pl';		# option parsing
do Getopts('b:c:d:fhl:n:');
die "$0: only one of -f and -h may be specified\n" if ($opt_f && $opt_h);

$USER = shift || die "user/password not specified\n";

if ($#ARGV >= 0)
{
	@stmt = @ARGV;
}
else
{
	print "Enter the statement to execute (^D to end):\n";
	@stmt = <STDIN>;
}

$, = "\t";			# default delimiter is a tab
$\ = "\n";			# each record terminated with newline

$db = $opt_b if defined($opt_b);			# set database
$ora_cache = $opt_c if defined($opt_c);			# set fetch cache
$, = $opt_d if defined($opt_d);				# set column delimiter
$= = $opt_l if defined($opt_l);				# set page length

# log into the database and execute the statement

$lda = &ora_login($db, $USER, '') || die "$ora_errstr\n";
$csr = &ora_open($lda, "@stmt") || die "$ora_errstr\n";

# print out any information which comes back

if (($nfields = &ora_fetch($csr)) > 0)	# does the statement return data?
{
	if ($opt_f)			# formatted output
	{
		# Build up format statements for the data

		# First, the header - a list of field names, formatted
		# in columns of the appropriate width

		$fmt = '';
		grep($fmt .= "%-${_}.${_}s|", &ora_lengths($csr));
		chop $fmt;
		$fmt = sprintf($fmt, &ora_titles($csr, 0));
		$format .= "format STDOUT_TOP =\n" . $fmt . "\n";

		# Then underlines for the field names

		$fmt =~ tr/|/-/c;
		$fmt =~ tr/|/+/;
		$format .= $fmt . "\n.\n";

		# Then for the data format, a @<<... field per column

		$fmt =~ tr/-+/<|/;
		$fmt =~ s/(^|\|)</\1@/g;
		$format .= "format STDOUT =\n" . $fmt . "\n";

		# Finally the variable associated with each column
		# Why doesn't Perl let us specify an array here?

		foreach $i (0 .. $nfields - 1)
		{
			$format .= "\$result[$i],";
		}
		chop $format;		# remove extraneous comma
		$format .= "\n.\n";

		eval($format);
	}
	elsif ($opt_h)
	{
		# Simple headers with underlines

		@titles = &ora_titles($csr, 0);
		grep(s/  *$//, @titles);
		print @titles;
		grep(tr//-/c, @titles);
		print @titles;
	}

	while (@result = &ora_fetch($csr))
	{
		grep(defined $_ || ($_ = $opt_n), @result) if $opt_n;
		($opt_f) ? (write) : (print @result);
	}
	warn "$ora_errstr\n" if ($ora_errno != 0);
}

# finish off neatly

do ora_close($csr);
do ora_logoff($lda);

__END__		# no need for perl even to scan the rest

##############################################################################

	# These next few lines are legal in both Perl and nroff.

.00;			# finish .ig
 
'di			\" finish diversion--previous line must be blank
.nr nl 0-1		\" fake up transition to first page again
.nr % 0			\" start at page 1
';<<'.ex'; ############## From here on it's a standard manual page ############
.TH SQL L "18th November 1992"
.ad
.nh
.SH NAME
sql \- execute an Oracle SQL statement from the command line
.SH SYNOPSIS
\fBsql\fP
[\fB\-b\fP\fIbase\fP]
[\fB\-c\fP\fIcache\fP]
[\fB\-d\fP\fIdelim\fP]
[\fB\-f\fP|\fB\-h\fP]
[\fB\-l\fP\fIpage_len\fP]
[\fB\-n\fP\fIstring\fP]
\fIname\fP\fB/\fP\fIpassword\fP
\fIstatement\fP
.SH DESCRIPTION
.I Sql
connects to an Oracle database
using the \fIname/password\fP supplied
and executes the given SQL \fIstatement\fP
displaying the result
on its standard output.

The \fB\-b\fP\fIbase\fP flag may be supplied to specify the database to be used.
If it is not given, the database specified by the environment variable
\fBORACLE_SID\fP or \fBTWO_TASK\fP is used.

The \fB\-c\fP\fIcache\fP flag may be supplied to set the size of fetch cache
to be used. If it is not given, the system default is used.

If the \fB\-n\fP\fIstring\fP flag is supplied,
\fBNULL\fP fields (in the \fIOracle\fP sense)
will replaced in the output by \fIstring\fP.
Normally, they are left blank.

The \fB\-f\fP and \fB\-h\fP flags may be used to modify the form of the output.
Without either flag, no field headers are printed
and fields are not padded.
With the \fB\-h\fP flag,
field headers are added to the top of the output,
but the format is otherwise unchanged.
With the \fB\-f\fP flag,
the output is formatted in a tabular form similar to that used by \fIsqlplus\fP,
except that all fields are left\-justified, regardless of their data type.
Column headers are printed at the top of each page;
a page is assumed to be 60 lines long,
but this may be overridden with the \fB\-l\fP\fIpage_len\fP flag.

Without the \fB\-f\fP flag, fields are separated with tabs;
this may be changed to any desired string (\fIdelim\fP)
using the \fB\-d\fP flag.
.SH ENVIRONMENT
The environment variable \fBORACLE_SID\fP or \fBTWO_TASK\fP
determines the Oracle database to be used
if the \fB\-b\fP\fIbase\fP flag is not supplied.
.SH DIAGNOSTICS
.in +5
.ti -5
\fBonly one of \-f and \-h may be specified\fP
.br
the \fB\-f\fP and \fB\-h\fP options are mutually exclusive,
but both were specified

.in -5
The only other diagnostics generated by \fIsql\fP are usage messages,
which should be self\-explanatory.
However, you may also encounter
error messages from Oraperl (unlikely) or from Oracle (more common).
See the \fIOracle Error Messages and Codes Manual\fP for details.
.SH NOTES
This program is only intended for use from the command line.
If you use it within a shell script
then you should consider rewriting your script in Oraperl
to use Perl's text manipulation and formatting commands.
.SH "SEE ALSO"
\fISQL Language Reference Manual\fP
.br
perl(1),
oraperl(1)
.SH AUTHOR
Kevin Stock,
.if t .ft C
<kstock@encore.com>
.if t .ft P
.ex
