ora2txt

MC, 5 August 2004: ora2txt is a simple script to query an Oracle database, using Oratcl and retrieve the results of a select statement as tab-delimited text. (This is one of the Oratcl examples.)


 #!/bin/sh
 # -*- tcl -*- \
 exec tclsh $0 ${1+"$@"}

 #
 # ora2txt: Output the results of a query in a textual format
 #

 package require Oratcl 4.0

 # If you want to hardcode a username/password combo, do so here:
 set username ""
 set password ""

 proc usage {} {
     global argv0
     puts stderr "Usage: $argv0 ?-v | -vv | -vvv? ?user/pass? QUERY"
     exit 1
 }

 proc output {text} {
     if {[catch {puts $text}]} then exit
 }


 proc main {} {
     global argv
     # Defaults
     global username password
     set verbosity 0

     set SQL  [lindex $argv end]
     set argv [lrange $argv 0 end-1]

     if {[llength $argv] > 0} {
         if {[regexp -- {^--?(v{1,3})(?:erbose)?$} [lindex $argv 0] => v]} {
             set verbosity [string length $v]
             set argv [lrange $argv 1 end]
         }

         if {[llength $argv] > 0} {
             foreach {username password} [split [lindex $argv 0] /] break
             set argv [lrange $argv 1 end]
         }
         if {[llength $argv]} then usage
     }

     if {[string length $SQL] == 0 ||
         [string equal $SQL "-"]   ||
         [string equal $SQL "--"]} {
         set SQL [read stdin]
     }

     set SQL [string trim $SQL]
     set SQL [string trimright $SQL ";"]

     set RE {^(?:\s*--[^\n]*\n)*\s*(select.+)?$}
     if {[regexp -nocase -- $RE $SQL => SQL] == 0} then usage

     set lh [oralogon $username/$password]
     set sh [oraopen $lh]
     oraconfig $sh nullvalue ""
     orasql $sh $SQL

     set cols [oracols $sh]
     if {$verbosity >= 2} {
         set len 0
         foreach col $cols {
             if {[string length $col] > $len} {
                 set len [string length $col]
             }
         }

         set counter 0
         set div [string repeat - 80]

         while {[orafetch $sh -datavariable data] == 0} {
             if {$counter} {
                 if {$verbosity == 3} {
                     set tag [format "\[^^%d / %dvv\]" \
                         [expr {$counter + 1}] \
                         [expr {$counter + 2}]]

                     set half [expr {(80 - [string length $tag]) / 2}]
                     set div  [string repeat - $half]
                     append div $tag
                     append div [string repeat - $half]

                     if {[string length $div] == 79} {
                         append div -
                     }
                 }

                 output \n$div\n
             }

             foreach col $cols datum $data {
                 output [format "%-${len}s %s" ${col}: $datum]
             }

             incr counter
         }
     } else {
         if {$verbosity == 1} {
             output [join $cols \t]
         }

         while {[orafetch $sh -datavariable data] == 0} {
             set row [list]
             foreach datum $data {
                 lappend row [string map [list \t " "] $datum]
             }
             output [join $row \t]
         }
     }
 }

 if {[catch main problem]} {
     puts stderr $problem
     exit 1
 }

LV Okay, so today I tried this out, in desperation because sql/plus was being such a pain to use. Here's how I ended up using it. I copied the entire page to a file. I removed all the text stuff at the top and bottom. I made certain that I fixed the #! line (so there was no leading space). I made certain that the tclsh in my PATH knew about oratcl.

I then tried running it. I didn't have much luck figuring out, initially, what I needed to do. Finally, this is what I did:

$ ./ora2txt -vvv - > ./outputora.txt
select * from mytable;
^D
$

and when I looked in outputora.txt, what I found was lines like this:

--------------------------------[^^217 / 218vv]---------------------------------

ID:         241
SYSID:      A123B
VERSION:    8.4.04.0
VERTYPE:    N
WIN9X:      0
WINNT:      1
WINXP:      1
MAC:        0
SOLARIS:    0
LINUX:      0
MAINFRAME:  0
POCKETPC:   0
VERSIONURL:
PREFIXHTML:
SUFFIXHTML:
VERSIONNOTE:
STOCKED:    N
SCRIPTED:   A
MACOS9:     0
WIN2KSERVER:
W2KSERVER:  0
WTS:        0

--------------------------------[^^218 / 219vv]---------------------------------

which was much better than sqlplus's output... Thank you!