home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume34 / shql / part01 < prev    next >
Encoding:
Text File  |  1993-01-05  |  31.0 KB  |  1,191 lines

  1. Newsgroups: comp.sources.misc
  2. From: root@candle.uucp (Bruce Momjian)
  3. Subject: v34i091:  shql - Interactively read and execute SQL commands, v1.1, Part01/01
  4. Message-ID: <1993Jan7.032641.9371@sparky.imd.sterling.com>
  5. X-Md4-Signature: e4ac8d117a071b7c1ff054cf369523b1
  6. Date: Thu, 7 Jan 1993 03:26:41 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: root@candle.uucp (Bruce Momjian)
  10. Posting-number: Volume 34, Issue 91
  11. Archive-name: shql/part01
  12. Environment: SQL, UNIX
  13. Supersedes: shql: Volume 25, Issue 15
  14.  
  15. Here is shql, version 1.1.  It has two added features, the ability to do
  16. SELECT's with multiple tables, and support for aggregates like AVG(),
  17. and SUM().
  18.  
  19. SHQL is an interactive SQL database engine.  Written as a shell script,
  20. SHQL interprets SQL commands and manipulates flat files based on those
  21. commands.  SHQL is limited in its understanding of SQL constructs.  All
  22. this is outlined in the README file contained in the distribution.  A
  23. demo file is also included to show some examples.
  24.  
  25. ------------------------------------------------------------------------
  26. #! /bin/sh
  27. # This is a shell archive.  Remove anything before this line, then feed it
  28. # into a shell via "sh file" or similar.  To overwrite existing files,
  29. # type "sh file -c".
  30. # Contents:  README CHANGES demo.shql shql
  31. # Wrapped by kent@sparky on Wed Jan  6 21:17:13 1993
  32. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin ; export PATH
  33. echo If this archive is complete, you will see the following message:
  34. echo '          "shar: End of archive 1 (of 1)."'
  35. if test -f 'README' -a "${1}" != "-c" ; then 
  36.   echo shar: Will not clobber existing file \"'README'\"
  37. else
  38.   echo shar: Extracting \"'README'\" \(4243 characters\)
  39.   sed "s/^X//" >'README' <<'END_OF_FILE'
  40. X                              S H Q L  version 1.1
  41. X
  42. X    Shql is a program that reads SQL commands interactively and
  43. X    executes those commands by creating and manipulating Unix files.
  44. X
  45. X    This program requires a bourne shell that understands functions,
  46. X    as well as awk, grep, cut, sort, uniq, join, wc, and sed.
  47. X
  48. X     This script can be invoked with the command 
  49. X
  50. X        shql [-q] {database name}
  51. X
  52. X      A directory must be created for the database before you may use it.
  53. X    This directory will house all data files for a single database.
  54. X    All datafiles are created with mode 666 ('rw-rw-rw-'), so create the
  55. X    directory with 777 ('rwxrwxrwx') if you want the database to be 
  56. X    sharable, and 700 ('rwx------') to be private.  Of course, multiple
  57. X    databases are possible.  A database called 'mydb' may be created
  58. X    as a directory $HOME/mydb, $HOME/shql/mydb, ./mydb, or as 
  59. X    $SHQL_ROOT/mydb, where $SHQL_ROOT is defined below.  The -q
  60. X    option turns off the display of headings so the output of shql
  61. X    can be used by other programs by caputuring all lines that begin
  62. X    the pipe symbol.
  63. X
  64. X      The program is patterned after Ingres' interactive sql terminal
  65. X    monitor program.  Terminal monitor commands begin with either a
  66. X    forward or back-slash.  Forward slashes may appear at the end of a
  67. X    commend line. Back-slashes are accepted for compatability.  The /g
  68. X    is the 'go' command, /p is print, and /q is quit.  Try 'help commands' 
  69. X    for a full list.  Because of this, if you need to put a slash as
  70. X    the second to last caracter on a line, you should add a space
  71. X    between the slash and the last character.
  72. X    
  73. X    To get started, invoke shql with a database name.  Use the directory 
  74. X    name you created above. Type
  75. X
  76. X        shql mydb
  77. X
  78. X    if the directory you created was 'mydb'.  Once shql starts up, you 
  79. X    should see the database name displayed, and then a '*'. At this
  80. X    point, the most valuable thing is to type help,
  81. X
  82. X        * help
  83. X        * /g
  84. X
  85. X    You may then go on.  The command 'help syntax' displays syntax
  86. X    for all SQL operations, and 'help commands' displays all shql
  87. X    workspace commands.  Try the demo.
  88. X
  89. X    Shql can execute only one operation at a time, but operations can
  90. X    be spread over several lines.
  91. X
  92. X    Shql operations are allow 'select' operations on multiple tables.
  93. X    Table names are read from left to write in select's 'from'
  94. X    section, so the tables should be ordered with the most central
  95. X    tables first.  In two-table joins, it doesn't matter.  In three
  96. X    table joins, if you join table A-to-B and B-to-C, B must not be
  97. X    the last table in the from clause, because shql will not be able
  98. X    to join tables A-C.  If you get the message 'Join not found, try
  99. X    reordering tables', this is probably the problem.  Also
  100. X    qualified field names are not understood, like tablename.fieldname,
  101. X    so if you are joining my_id in table A with my_id in table B, just
  102. X    say 'my_id = my_id'.  Views can also be used to create
  103. X    multi-table selects.
  104. X
  105. X    Subselects are implemented, but must be the last operand of a
  106. X    'where' clause, most useful with 'in'.
  107. X
  108. X    In most cases, commas are optional.  NULLs are not implemented.
  109. X    Aggregates like AVG() are implemented, but not with GROUP BY.
  110. X
  111. X    When INSERTing strings that contain the characters !,=,>,<,(, or ),
  112. X    spaces or backslashes may be added during the insert.  This is a
  113. X    side-effect of the string manipulation needed to properly
  114. X    parse the command parameters.
  115. X
  116. X    This SQL is type-less, so specify just the column width when creating
  117. X    tables.  This is used only for display purposes.  Shql is
  118. X    case-sensitive, and expects SQL key words to be in lower case.
  119. X    
  120. X    Commands can be piped into shql, and the table data files are
  121. X    tab delimited, so awk scripts can be used to generate reports 
  122. X    directly from the tables.  To operate on non-shql data files,
  123. X    create a dummy table with the proper fields, then copy your file
  124. X    into your shql data directory, replacing your delimiters with
  125. X    tabs, then run shql on the table, and convert the table back to 
  126. X    its original format.  Grave accents (`) may be used to execute 
  127. X    unix command from with shql.  Environment variables may also be
  128. X    used. See the demo for an example, i.e. "cat demo.shql | shql mydb".
  129. X
  130. X    If you have comments, suggestions, or bug reports contact:
  131. X
  132. X        Bruce Momjian, root@candle.uucp (root%candle.uucp@bts.com)
  133. END_OF_FILE
  134.   if test 4243 -ne `wc -c <'README'`; then
  135.     echo shar: \"'README'\" unpacked with wrong size!
  136.   fi
  137.   # end of 'README'
  138. fi
  139. if test -f 'CHANGES' -a "${1}" != "-c" ; then 
  140.   echo shar: Will not clobber existing file \"'CHANGES'\"
  141. else
  142.   echo shar: Extracting \"'CHANGES'\" \(506 characters\)
  143.   sed "s/^X//" >'CHANGES' <<'END_OF_FILE'
  144. XNew to version 1.1
  145. X-----------------------------------
  146. XNow runs under ksh as well as sh.
  147. XMulti-table joins possible without creating views
  148. XAggregates now supported
  149. XLooks in your $HOME/shql/ for database name also
  150. XExecution operators are now '\' and '/',with '/' now possible the end 
  151. X    of a line
  152. XWhite-space is not required as it was before
  153. XNew -q option removes table headers, so only taking output that begins
  154. X    with '|' gets you all the data
  155. XDelete syntax now requires a FROM, as it should have all along
  156. END_OF_FILE
  157.   if test 506 -ne `wc -c <'CHANGES'`; then
  158.     echo shar: \"'CHANGES'\" unpacked with wrong size!
  159.   fi
  160.   # end of 'CHANGES'
  161. fi
  162. if test -f 'demo.shql' -a "${1}" != "-c" ; then 
  163.   echo shar: Will not clobber existing file \"'demo.shql'\"
  164. else
  165.   echo shar: Extracting \"'demo.shql'\" \(2170 characters\)
  166.   sed "s/^X//" >'demo.shql' <<'END_OF_FILE'
  167. X# Demo for SHQL, version 0.60
  168. X# Create table customer
  169. Xcreate table customer (
  170. X    name 30,
  171. X    age  3,
  172. X    status 1)
  173. X/p/g
  174. X
  175. X# Put one person in the table
  176. Xinsert into customer values ( 'Fred', 32, 'G' )/p/g
  177. X
  178. X# Study the table
  179. Xhelp customer
  180. X/p/g
  181. Xselect * from customer/p/g
  182. X
  183. X# Add two more people
  184. Xinsert into customer values 
  185. X( 'Barney', 29, 'G', 'Wilma', 28, 'D' )
  186. X/p/g
  187. Xprint customer
  188. X/p/g
  189. X
  190. X# Get customers with 'G' status
  191. Xselect * from customer
  192. Xwhere status = 'G' /p/g
  193. X
  194. X# Get sorted list of customers by age
  195. Xselect * from customer
  196. Xorder by age num
  197. X/p/g 
  198. X
  199. X# Make a table to hold customer status codes and their descriptions
  200. Xcreate table codes ( 
  201. X    code 1,
  202. X    description 10 )
  203. X/p/g
  204. X
  205. X# Insert status codes
  206. Xinsert into codes values 
  207. X( 'G', 'Good', 'B', 'Bad', 'D', 'Dead Beat' )
  208. X/p/g
  209. X
  210. X# Create a view so we can see the customer name and status description
  211. Xcreate view custstat ( customer.status = codes.code )
  212. X/p/g
  213. X
  214. X# Look at the table
  215. Xhelp custstat
  216. X/p/g
  217. Xselect * from custstat
  218. X/p/g
  219. X
  220. Xselect * 
  221. Xfrom customer, codes
  222. Xwhere status = code
  223. X/p/g
  224. X
  225. X# Replace 'Barney' with 'Bad Bart'
  226. Xupdate customer 
  227. Xset name = 'Bad Bart', status = 'X' 
  228. Xwhere age = 29
  229. X/p/g
  230. X
  231. Xprint customer
  232. X/p/g
  233. X
  234. X# Get all customers that have invalid status'es
  235. Xselect * from customer
  236. Xwhere status not in select code 
  237. X            from codes
  238. X/p/g
  239. X
  240. X# Remove 'Fred'
  241. Xdelete from customer
  242. Xwhere age = 32
  243. X/p/g
  244. X
  245. X# Get rid of view 
  246. Xdrop view custstat
  247. X/p/g
  248. X
  249. X# Create a holding table for old customers
  250. Xcreate table oldcust (
  251. X    name 30,
  252. X    status 1 )
  253. X/p/g
  254. X
  255. X# Copy old customer to new table
  256. Xinsert into oldcust ( 
  257. X    name status )
  258. Xselect name status 
  259. Xfrom customer
  260. Xwhere age > 28
  261. X/p/g
  262. X
  263. Xselect avg(age)
  264. Xfrom customer
  265. X/p/g
  266. X
  267. Xselect name
  268. Xfrom customer
  269. Xwhere age = select min(age)
  270. X        from customer
  271. X/p/g
  272. X
  273. X# Look at table
  274. Xprint oldcust
  275. X/p/g
  276. X
  277. X# Delete customers moved over
  278. Xdelete from customer
  279. Xwhere age > 28
  280. X/p/g
  281. X
  282. Xprint customer
  283. X/p/g
  284. X
  285. X# Try a union of the two tables
  286. Xselect name age
  287. Xfrom customer
  288. Xunion
  289. Xselect name status 
  290. Xfrom oldcust
  291. X/p/g
  292. X
  293. X# Show example of executing Unix commands
  294. Xinsert into customer 
  295. Xvalues ( '`date`', `ls / | wc -l`, 'Y' )
  296. X/p/g
  297. Xprint customer
  298. X/p/g
  299. X# Clean up
  300. Xdrop table codes
  301. X/p/g
  302. Xdrop table customer
  303. X/p/g
  304. Xdrop table oldcust
  305. X/p/g
  306. X/q    
  307. END_OF_FILE
  308.   if test 2170 -ne `wc -c <'demo.shql'`; then
  309.     echo shar: \"'demo.shql'\" unpacked with wrong size!
  310.   fi
  311.   # end of 'demo.shql'
  312. fi
  313. if test -f 'shql' -a "${1}" != "-c" ; then 
  314.   echo shar: Will not clobber existing file \"'shql'\"
  315. else
  316.   echo shar: Extracting \"'shql'\" \(20449 characters\)
  317.   sed "s/^X//" >'shql' <<'END_OF_FILE'
  318. X#!/bin/sh
  319. X# use /bin/sh or /bin/ksh
  320. X#
  321. X# shql - version 1.1
  322. X#
  323. X
  324. X# DEFINE THESE
  325. XSHQL_ROOT="/u/shql"        # system-wide database location
  326. XEDITOR="${EDITOR:=/usr/bin/vi}" # default editor if EDITOR not defined
  327. XSHELL="${SHELL:=/bin/sh}"     # default editor if EDITOR not defined
  328. X
  329. X# Unix table file postfixes:  @ is attrib, ~ is data, % is view
  330. X
  331. XDEBUG="N"    # set to Y for debugging
  332. X
  333. X[ "$DEBUG" = "Y" ] && set -x           # uncomment for debugging
  334. X#set -v
  335. XUMASK=`umask`
  336. Xumask 0000        # share database
  337. Xtrap "echo \"Goodbye\" ; \
  338. X    rm -f /tmp/$$ /tmp/$$row /tmp/$$join*" 0 1 2 3 15
  339. Xset -h            # remember functions
  340. X
  341. Xif echo '\c' | grep -s c ; then        # to adapt to System V vs. BSD 'echo'
  342. X    NOCR1='-n'            # BSD
  343. X    NOCR2=""
  344. Xelse
  345. X    NOCR1=""            # System V
  346. X    NOCR2='\c'
  347. Xfi
  348. XNL='
  349. X'
  350. XTAB='    '
  351. Xexport _IFS TABLE CMD NOCR1 NOCR2 NL TAB
  352. X_IFS="$IFS"
  353. X
  354. Xif [ "X$1" = "X-q" ] 
  355. Xthen    QUIET="Y"
  356. X    shift
  357. Xfi
  358. X
  359. Xif [ "X$1" = "X" ]
  360. Xthen    echo "Missing database name." 1>&2
  361. X    echo "The database name must be a directory under $HOME/shql" 1>&2
  362. X    echo "    or a directory under $SHQL_ROOT" 1>&2
  363. X    exit 1
  364. Xfi
  365. Xecho "Database: $1"
  366. X
  367. Xif [ -d $HOME/shql/$1 ]
  368. Xthen    cd $HOME/shql/$1
  369. Xelif [ -d $SHQL_ROOT/$1 ]
  370. Xthen    cd $SHQL_ROOT/$1
  371. Xelif [ -d $HOME/$1 ]
  372. Xthen    cd $HOME/$1
  373. Xelif [ -d $1 ]
  374. Xthen    cd $1
  375. Xelse     echo "Unknown database ($1)" 1>&2
  376. X    echo "The database name must be a directory under $HOME/shql" 1>&2
  377. X    echo "    or a directory under $SHQL_ROOT" 1>&2
  378. X    exit 1
  379. Xfi
  380. X
  381. X
  382. X#
  383. X#**************************************************************************
  384. X# syntax
  385. X#**************************************************************************
  386. Xsyntax(){
  387. X    case "$1" in
  388. X        create)    cat <<"END"
  389. XCREATE TABLE table_name (
  390. X    column_name column_width 
  391. X    {, ...} 
  392. X)     
  393. Xor
  394. XCREATE VIEW view_name (
  395. X    table_or_view1.column1 = table_or_view2.column2
  396. X)
  397. XEND
  398. Xreturn 0
  399. X;;
  400. X        delete) cat <<"END"
  401. XDELETE 
  402. XFROM table_name    
  403. X{ WHERE where_clause }
  404. XEND
  405. Xreturn 0
  406. X;;
  407. X        drop) cat <<"END"
  408. XDROP TABLE table_name
  409. Xor
  410. XDROP VIEW view_name
  411. XEND
  412. Xreturn 0
  413. X;;
  414. X        edit) cat <<"END"
  415. XEDIT table_name
  416. Xis a non-standard method of changing a table's field names or display widths.
  417. XEND
  418. Xreturn 0
  419. X;;
  420. X        help)    cat <<"END"
  421. XHELP ALL
  422. Xor
  423. XHELP TABLES 
  424. Xor
  425. XHELP VIEWS
  426. Xor
  427. XHELP COMMANDS
  428. Xor
  429. XHELP [CREATE | DELETE | DROP | INSERT | SELECT | UPDATE | WHERE | PRINT | EDIT]
  430. Xor
  431. XHELP table_name
  432. XCommands must appear in lower case.
  433. XEND
  434. Xreturn 0
  435. X;;
  436. X        insert) cat <<"END"
  437. XINSERT INTO table_name 
  438. X    { ( column_name, ... ) }
  439. XVALUES ( expression, ...)
  440. Xor        
  441. XINSERT INTO table_name 
  442. X    { ( column_name, ... ) }
  443. Xsubselect
  444. XEND
  445. Xreturn 0
  446. X;;
  447. X        print) cat <<"END"
  448. XPRINT table_name 
  449. Xis a non-standard synonym for SELECT * FROM table_name.
  450. XEND
  451. Xreturn 0
  452. X;;
  453. X        select) cat <<"END"
  454. XSELECT { DISTINCT } 
  455. X    [ column_name {,...} | * ]
  456. XFROM [ table_name | view_name ]
  457. X{ WHERE where_clause }
  458. X{ ORDER BY column_name { NUM } { ASC | DESC } {, ... }
  459. X{ UNION select statement }
  460. X'NUM' is a non-standard method for sorting numeric fields.
  461. XEND
  462. Xreturn 0
  463. X;;
  464. X        update) cat <<"END"
  465. XUPDATE table_name
  466. XSET column_name = expression {, ... }
  467. X{ WHERE where_clause }
  468. XEND
  469. Xreturn 0
  470. X;;
  471. X        where) cat <<"END"
  472. XWHERE [ column_name | value ] [ =, !=, >, <, >=, <=, and, or, not, in ]
  473. X      [ column_name | value | subselect ]
  474. XParentheses may be used to group expressions.  
  475. XEND
  476. Xreturn 0
  477. X;;
  478. X        syntax)    syntax commands; echo
  479. X            syntax create; echo
  480. X            syntax delete; echo
  481. X            syntax drop; echo
  482. X            syntax insert; echo
  483. X            syntax select; echo
  484. X            syntax update; echo
  485. X            syntax where; echo
  486. X            syntax print; echo
  487. X            syntax edit; echo
  488. X            return 0
  489. X            ;;
  490. X    esac
  491. X    return 1
  492. X}
  493. X
  494. X#
  495. X#**************************************************************************
  496. X# lookup_field
  497. X#**************************************************************************
  498. Xlookup_field(){
  499. X    if [ ! -f $TABLE% ]
  500. X    then    RESULT="`grep -n \"^$1    \" $TABLE@`"
  501. X    else     RESULT="`grep -n \"^$1    \" $TABLE@ | sed 1q`"
  502. X    fi
  503. X    if [ ! "$RESULT" ] 
  504. X    then     OUTFIELD="$1"
  505. X        return 1
  506. X    else    OUTFIELDNUM="`expr "$RESULT" : '\([^:]*\)'`"
  507. X        OUTFIELD="\$$OUTFIELDNUM" 
  508. X        return 0
  509. X    fi
  510. X}
  511. X
  512. X#
  513. X#**************************************************************************
  514. X# do_aggreg
  515. X#**************************************************************************
  516. Xdo_aggreg(){
  517. X    if     [ "X$1" = 'Xsum' ]
  518. X    then    AGGREG='total'
  519. X    elif     [ "X$1" = 'Xavg' ]
  520. X    then     AGGREG='(total/cnt)'
  521. X    elif     [ "X$1" = 'Xcount' ]
  522. X    then     AGGREG='cnt'
  523. X    elif     [ "X$1" = 'Xmin' ]
  524. X    then     AGGREG='min'
  525. X    elif     [ "X$1" = 'Xmax' ]
  526. X    then     AGGREG='max'
  527. X    else    return 1
  528. X    fi
  529. X    [ "X$2" != "X(" -o "X$4" != "X)" ] && \
  530. X        echo "Bad aggregate syntax" 1>&2 && syntax select && return 1
  531. X    AGGFIELD="$3"
  532. X    shift 4
  533. X    lookup_field "$AGGFIELD"
  534. X    [ "$?" -ne 0 ] && echo "Bad field name ($1)" 1>&2 && return 1
  535. X    while [ $# -ne 0 ]
  536. X    do    
  537. X        [ "X$1" = "Xwhere" ] && break;
  538. X        [ "X$1" = "Xorder" ] && break;
  539. X        [ "X$1" = "Xunion" ] && break;
  540. X        shift
  541. X    done
  542. X
  543. X    OUTFIELD=`( SUBSELECT="Y" ; AGGREGATE="Y"; \
  544. X        select_ "select" "$AGGFIELD" "from" "$TABLE" "$@") | \
  545. X        awk -F"    " \
  546. X        'NR == 1 { min = $1; max = $1 }
  547. X             { cnt += 1; total += $1 }
  548. X        $1 < min { min = $1 }
  549. X        $1 > max { max = $1 }
  550. X        END     { printf "%s%s%s", "\"", '$AGGREG', "\"" }'`
  551. X    if [ `expr "$RESULT" : '[^    ]*    \(.*\)'` -lt 10 ]
  552. X    then    RESULT="$AGGFIELD    10"
  553. X    fi
  554. X    return 0
  555. X}
  556. X
  557. X#
  558. X#**************************************************************************
  559. X# do_join 
  560. X#**************************************************************************
  561. Xdo_join(){
  562. X    update_view "$1"
  563. X    TABLE="$1"
  564. X    lookup_field "$2" 
  565. X    [ "$?" -ne 0 ] && echo "Bad view specifcation ($1.$2)" 1>&2 && return 1
  566. X    JFIELD1="$OUTFIELDNUM"
  567. X    JFIELD1L1="`expr $JFIELD1 - 1`"
  568. X    update_view "$3"
  569. X    TABLE="$3"
  570. X    lookup_field "$4" 
  571. X    [ "$?" -ne 0 ] && echo "Bad view specifcation ($3.$4)" 1>&2 && return 1
  572. X    JFIELD2="$OUTFIELDNUM"
  573. X    JFIELD2L1="`expr $JFIELD2 - 1`"
  574. X
  575. X    ( grep "^$2    " $1@ ;
  576. X      grep -v "^$2    " $1@ ;
  577. X      grep -v "^$4    " $3@ ) > $5@
  578. X    sort -t\     +$JFIELD2L1 $3~ > /tmp/$$
  579. X    sort -t\     +$JFIELD1L1 $1~ | \
  580. X        join -t\     -j1 $JFIELD1 -j2 $JFIELD2 \
  581. X                        - /tmp/$$ > $5~
  582. X}
  583. X
  584. X#
  585. X#**************************************************************************
  586. X# update_view
  587. X#**************************************************************************
  588. Xupdate_view(){
  589. X    [ ! -f "$1%" ] && return 1
  590. X    ( do_join `cat $1%` )
  591. X}
  592. X
  593. X#
  594. X#**************************************************************************
  595. X# where
  596. X#**************************************************************************
  597. Xwhere(){
  598. X    shift
  599. X    while [ $# -gt 0 -a "$1" != "order" -a "$1" != "union" ]
  600. X    do
  601. X        if [ "X$1" = "Xselect" ]
  602. X        then
  603. X            set X `( SUBSELECT="Y" ;select_ "$@")`
  604. X            if [ "$?" -eq 0 ]
  605. X            then     shift
  606. X            else     return 1
  607. X            fi
  608. X        fi
  609. X        case "$1" in
  610. X            and)     WHERE="$WHERE && ";;
  611. X            or)    WHERE="$WHERE || ";;
  612. X            not)    WHERE="$WHERE !" ;;
  613. X            =)    WHERE="$WHERE == ";;
  614. X            'in')     shift
  615. X                set X `( SUBSELECT='Y';select_ "$@" )`
  616. X                if [ "$?" -eq 0 ]
  617. X                then     shift
  618. X                else     return 1
  619. X                fi
  620. X                INWHERE=""
  621. X                COMP="=="
  622. X                LOGIC="||"
  623. X                [ "X$LAST" = "Xnot" ] && COMP="=" && LOGIC="&&"
  624. X                for VALUE
  625. X                do
  626. X                    [ "X$INWHERE" != "X" ] && 
  627. X                        INWHERE="$INWHERE $LOGIC"
  628. X                    INWHERE="$INWHERE ($WHERE$COMP $VALUE) "
  629. X                done
  630. X                WHERE="$INWHERE"
  631. X                break;;
  632. X            *)    lookup_field "$1"
  633. X                WHERE="$WHERE $OUTFIELD";;
  634. X        esac
  635. X        LAST="$1"
  636. X        shift
  637. X    done 
  638. X    [ "$WHERE" ] && WHERE=" ( $WHERE ) " && return 0
  639. X    echo "Missing 'where' clause" 1>&2
  640. X    syntax where
  641. X    return 1
  642. X}
  643. X
  644. X#
  645. X#**************************************************************************
  646. X# help
  647. X#**************************************************************************
  648. Xhelp(){
  649. X    if [ ! "$2" ]
  650. X    then    echo "Ambiguous syntax, try:" 1>&2 ; syntax help
  651. X    elif [ "$2" = "all" ]
  652. X    then    ls *@ *% 2>/dev/null | cut -d@ -f1 | cut -d% -f1 | uniq
  653. X    elif [ "$2" = "tables" ] 
  654. X    then    ls *@ *% 2>/dev/null | cut -d@ -f1 | cut -d% -f1 | uniq -u 
  655. X    elif [ "$2" = "views" ] 
  656. X    then    ls *% 2>/dev/null | cut -d% -f1 
  657. X    elif [ "$2" = "commands" ]
  658. X    then    cat << "END"
  659. X/p is print
  660. X/g is go(execute)
  661. X/q is quit
  662. X/e is edit
  663. X/i is include
  664. X/w is write
  665. X/r is reset(clear)
  666. X/s is shell
  667. X/p/g print and go
  668. XThe number sign(#) may be used at the start of a line for comments.
  669. XEND
  670. X    else    syntax $2 && return
  671. X        TABLE="$2"
  672. X        update_view "$TABLE"
  673. X        if [ -f "$2@" ] 
  674. X        then    echo "$NL <$2>" && cat "$2@"
  675. X            [ -f "${2}%" ] &&echo $NOCR1 "$NL View:    $NOCR2" && 
  676. X                set X `cat $2%` && shift &&
  677. X                echo "$1.$2 = $3.$4"
  678. X            echo "$NL Rows:    "`cat $TABLE~ | wc -l`
  679. X        else     echo "$TABLE does not exist." 1>&2
  680. X            syntax help
  681. X        fi
  682. X    fi
  683. X}
  684. X
  685. X#
  686. X#**************************************************************************
  687. X# create
  688. X#**************************************************************************
  689. Xcreate(){
  690. X    shift
  691. X    if [ -f "$2@" -o -f "$2%" ]
  692. X    then    echo "Table already exists." 1>&2
  693. X    elif [ "X$1" = "Xview" -a $# -gt 2 ]
  694. X    then    shift
  695. X        if [ $# -ne 6 ]
  696. X        then     syntax create
  697. X        else     
  698. X            [ "X$2" != "X(" ] && echo "Bad syntax" 1>&2 && 
  699. X                            syntax create && return
  700. X            TABLE1="`expr $3 : '\([^\.]*\)'`"
  701. X            FIELD1="`expr $3 : '[^\.]*.\(.*\)'`"
  702. X            TABLE="$TABLE1"
  703. X            lookup_field "$FIELD1" 
  704. X            [ "$?" -ne 0 ] && echo "Bad table or field name" 1>&2 &&
  705. X                                    return
  706. X            [ "X$4" != "X=" ] && echo "Bad syntax" 1>&2 && 
  707. X                            syntax create && return
  708. X            TABLE2="`expr $5 : '\([^\.]*\)'`"
  709. X            FIELD2="`expr $5 : '[^\.]*.\(.*\)'`"
  710. X            TABLE="$TABLE2"
  711. X            lookup_field "$FIELD2" 
  712. X            [ "$?" -ne 0 ] && echo "Bad table or field name" 1>&2 &&
  713. X                                    return
  714. X            [ "X$2" != "X(" ] && echo "Bad syntax" 1>&2 && 
  715. X                            syntax create && return
  716. X            echo "$TABLE1 $FIELD1 $TABLE2 $FIELD2 $1" > $1%
  717. X            update_view "$1"            
  718. X        fi
  719. X        echo "OK"
  720. X    elif [ "X$1" = "Xtable" -a $# -ge 5 ] 
  721. X    then
  722. X        [ "X$3" != "X(" ] && echo "Bad syntax" 1>&2 && 
  723. X                            syntax create && return
  724. X        TABLE="$2"
  725. X        shift 3
  726. X        > $TABLE@
  727. X        > $TABLE~
  728. X        while [ $# -ge 2 ]
  729. X        do
  730. X            echo "$1    $2" >> $TABLE@
  731. X            shift 2
  732. X        done
  733. X        [ "X$1" != "X)" ] && echo "Bad syntax" 1>&2 && 
  734. X                    rm -f $TABLE@ && syntax create && return
  735. X        echo "OK"
  736. X    else 
  737. X        echo "Improper syntax ($1)" 1>&2
  738. X        syntax create
  739. X    fi
  740. X    return
  741. X}
  742. X
  743. X#
  744. X#*************************************************************************
  745. X# drop
  746. X#**************************************************************************
  747. Xdrop(){
  748. X    [ "$2" != "table" -a "$2" != "view" ] && 
  749. X        echo "Syntax error." 1>&2 && syntax drop && return
  750. X    [ "$2" = "table" -a -f "$3%" ] &&
  751. X        echo "Can not drop, $2 is a view, not a table" 1>&2 && return
  752. X    [ "$2" = "view" -a ! -f "$3%" ] &&
  753. X        echo "Can not drop, $2 is not a view" 1>&2 && return
  754. X    if [ -f "$3@" -o -f "$3%" ] 
  755. X    then    rm -f $3@ $3~ $3%
  756. X        echo "OK"
  757. X    else      echo "No such table" 1>&2
  758. X    fi
  759. X}
  760. X
  761. X#
  762. X#**************************************************************************
  763. X# insert
  764. X#**************************************************************************
  765. Xinsert(){
  766. X    shift
  767. X    [ "X$1" != "Xinto" ] && echo "Improper syntax ($1)" 1>&2 && 
  768. X        syntax insert && return
  769. X    shift
  770. X    TABLE="$1"
  771. X    update_view "$TABLE" && echo "Can not insert into a view" 1>&2 && return
  772. X    [ ! -f "$TABLE@" ] && echo "Table does not exist" 1>&2 && return
  773. X    shift
  774. X    ATTRIB="`cat $TABLE@ | wc -l`"
  775. X    XASGN=""
  776. X    XECHO="echo \""
  777. X    if [ $# -gt 0 -a "X$1" = "X(" ]
  778. X    then    ATTRIB2="0"
  779. X        shift
  780. X        while [ $# -gt 0 -a "X$1" != "X)" ]
  781. X        do
  782. X            lookup_field "$1" 
  783. X            [ "$?" -ne 0 ] && echo "Bad field name. ($1)" 1>&2 && 
  784. X                                    return 
  785. X            XASGN="$XASGN X$OUTFIELDNUM=\`eval echo \$1\` ; shift;"
  786. X            shift
  787. X            ATTRIB2=`expr $ATTRIB2 + 1`
  788. X        done
  789. X        [ "X$1" != "X)" ] && echo "Syntax error ($1)" 1>&2 && 
  790. X                        syntax insert && return
  791. X        shift
  792. X        POS="1"
  793. X        while [ "$POS" -le "$ATTRIB" ]
  794. X        do
  795. X            eval X$POS=""
  796. X            [ "$POS" != "1" ] && XECHO="$XECHO\$TAB"
  797. X            XECHO="$XECHO\$X$POS"
  798. X            POS=`expr $POS + 1`
  799. X        done
  800. X        XECHO="$XECHO\""
  801. X        ATTRIB="$ATTRIB2"
  802. X    fi    
  803. X    if [ "X$1" = "Xselect" ]
  804. X    then     eval set X "`( SUBSELECT='Y' ; select_ "$@" )` \)"
  805. X        shift
  806. X    elif [ "X$1" != "Xvalues" -o "X$2" != 'X(' ]  
  807. X        then     echo "Improper syntax ($1)" 1>&2 && syntax insert && 
  808. X                                    return
  809. X    else    shift 2
  810. X    fi
  811. X    for LAST do 
  812. X    : ; done
  813. X    [ "X$LAST" != "X)" ] && 
  814. X        echo "Improper syntax" 1>&2 && syntax insert && return
  815. X    if [ "`expr \( $# - 1 \) % $ATTRIB`" -ne 0 ]
  816. X    then     echo "Incorrect number of values." 1>&2
  817. X    else    ROWS="`expr \( $# - 1 \) / $ATTRIB`"
  818. X        while [ $# -gt 1 ]
  819. X        do    
  820. X            if [ "$XASGN" = "" ]
  821. X            then     
  822. X                echo $NOCR1 "`eval echo $1`$NOCR2" >> $TABLE~ 
  823. X                shift
  824. X                while [ "`expr \( $# - 1 \) % $ATTRIB`" -ne 0 ]
  825. X                do
  826. X                    echo $NOCR1 "$TAB`eval echo $1`$NOCR2"\
  827. X                                 >> $TABLE~
  828. X                    shift
  829. X                done
  830. X                echo "" >> $TABLE~
  831. X            else    eval $XASGN
  832. X                eval $XECHO >> $TABLE~
  833. X            fi
  834. X        done
  835. X        echo "($ROWS rows)"            
  836. X    fi
  837. X}
  838. X
  839. X#
  840. X#*************************************************************************
  841. X# delete
  842. X#**************************************************************************
  843. Xdelete(){
  844. X    TABLE="$3"
  845. X    [ "X$2" != "Xfrom" ] && echo "Improper syntax ($2)" 1>&2 && 
  846. X        syntax delete && return
  847. X    update_view "$TABLE" && echo "You can not delete from a view." 1>&2 &&
  848. X                                    return  
  849. X    [ ! -f "$TABLE@" ] && echo "$TABLE does not exist." 1>&2 && return
  850. X    WHERE=""
  851. X    if [ "X$4" = "Xwhere" ]
  852. X    then     shift 3
  853. X        where "$@" && 
  854. X        awk -F"    " "! $WHERE { cnt += 1 ; print } 
  855. X            END { printf \"( %1d rows.)\\n\", (NR - cnt) \
  856. X            >\"/tmp/$$row\" }" $TABLE~ > /tmp/$$ && 
  857. X            mv /tmp/$$ $TABLE~ && cat /tmp/$$row
  858. X    else    echo '('`cat $TABLE~ | wc -l`' rows)' 
  859. X        > $TABLE~
  860. X    fi
  861. X}
  862. X
  863. X#
  864. X#*************************************************************************
  865. X# update
  866. X#**************************************************************************
  867. Xupdate(){
  868. X    TABLE="$2"
  869. X    update_view "$TABLE" && echo "Can not update a view." 1>&2 && return
  870. X    [ ! -f "$TABLE@" ] && echo "$TABLE does not exit." 1>&2 && return
  871. X    [ "X$3" != "Xset" ] && echo "Improper syntax." 1>&2 && syntax update && 
  872. X                                    return
  873. X    shift 3
  874. X    ASSIGN=""
  875. X    while [ $# -gt 0 -a "X$1" != "Xwhere" ]
  876. X    do
  877. X        lookup_field "$1" && [ "X$2" = "X=" ] && ASSIGN="$ASSIGN ; "
  878. X        ASSIGN="$ASSIGN $OUTFIELD"
  879. X        shift
  880. X    done
  881. X    WHERE=""
  882. X    if [ "X$1" = "Xwhere" ] 
  883. X    then     where "$@" || return 
  884. X    fi
  885. X    awk -F"    " "BEGIN { OFS = \"    \" }
  886. X        $WHERE     { $ASSIGN; cnt += 1 }
  887. X            { print } 
  888. X        END     { printf \"( %1d rows)\\n\", cnt >\"/tmp/$$row\" }" \
  889. X        $TABLE~ > /tmp/$$ && 
  890. X            mv /tmp/$$ $TABLE~ && cat /tmp/$$row
  891. X}
  892. X
  893. X#
  894. X#**************************************************************************
  895. X# select_
  896. X#**************************************************************************
  897. Xselect_(){
  898. X[ "$DEBUG" = "Y" ] && set -x           # uncomment for debugging
  899. X    UNION="Y"
  900. X    while [ "$UNION" != "" ]
  901. X    do
  902. X        INAGG=""
  903. X        FROM=""
  904. X        UNION=""
  905. X        TABLE=""
  906. X        for ATABLE
  907. X        do
  908. X            [ "X$ATABLE" = "Xwhere" ] && break
  909. X            [ "X$ATABLE" = "Xorder" ] && break
  910. X            [ "X$ATABLE" = "Xunion" ] && break
  911. X            [ "X$ATABLE" = "Xfrom" ] && FROM="Y" && continue
  912. X            if [ "$FROM" ]
  913. X            then
  914. X            [ ! -f "$ATABLE@" ] && \
  915. X            echo "$ATABLE does not exist." 1>&2 && return 1
  916. X            if [ ! "$TABLE" ]
  917. X            then     TABLE="$ATABLE"
  918. X            else    JTABLE="$TABLE"
  919. X                PREV=""
  920. X                PPREV=""
  921. X                FOUND=""
  922. X                for GETJ
  923. X                do
  924. X                    if [ "$PREV" = "=" ]
  925. X                    then
  926. X                    TABLE="$JTABLE"
  927. X                    lookup_field "$PPREV" &&
  928. X                    TABLE="$ATABLE" &&
  929. X                    lookup_field "$GETJ" &&
  930. X                    FOUND="Y1" &&
  931. X                    break
  932. X                    TABLE="$ATABLE"
  933. X                    lookup_field "$PPREV" &&
  934. X                    TABLE="$JTABLE" &&
  935. X                    lookup_field "$GETJ" &&
  936. X                    FOUND="Y2" &&
  937. X                    break
  938. X                    fi
  939. X                    PPREV="$PREV"
  940. X                    PREV="$GETJ"
  941. X                done
  942. X                [ ! "$FOUND" ] &&
  943. X                echo "Join not found, \c" &&
  944. X                echo "try reordering tables." 1>&2 && return 1
  945. X                if [ "$FOUND" = "Y1" ]
  946. X                then
  947. X    echo "$JTABLE    $PPREV    $ATABLE    $GETJ    /tmp/$$join2" >/tmp/$$join2%
  948. X                else
  949. X    echo "$ATABLE    $PPREV    $JTABLE    $GETJ    /tmp/$$join2" >/tmp/$$join2%
  950. X                fi
  951. X                update_view /tmp/$$join2
  952. X                mv /tmp/$$join2~ /tmp/$$join~
  953. X                mv /tmp/$$join2@ /tmp/$$join@
  954. X                expr "$RESULT" : '[^:]:*\(.*\)' >>/tmp/$$join@
  955. X                cut -d\     -f1 /tmp/$$join~ | \
  956. X                    paste /tmp/$$join~ - >/tmp/$$
  957. X                mv /tmp/$$ /tmp/$$join~
  958. X                TABLE="/tmp/$$join"
  959. X            fi
  960. X            fi
  961. X        done
  962. X        [ ! "$FROM" ] && echo "Syntax error." 1>&2 && syntax select &&
  963. X                                return 1
  964. X        update_view "$TABLE"
  965. X         shift
  966. X        DISTINCT=""
  967. X        [ "X$1" = "Xdistinct" ] && DISTINCT="Y" && shift
  968. X        FIELDS=""
  969. X        PRINTF=""
  970. X        while [ "X$1" != "Xfrom" ]
  971. X        do
  972. X            if [ "X$1" = 'X*' ]
  973. X            then    shift
  974. X                set X `cat $TABLE@ | cut -d\     -f1` "$@" 
  975. X                shift
  976. X            else    lookup_field "$1"
  977. X                if [ "$?" -ne 0 ]
  978. X                then     do_aggreg "$@"
  979. X                    if [ "$?" -eq 0 ]
  980. X                    then    INAGG="Y"
  981. X                        shift 3
  982. X                    else 
  983. X                      echo "Bad field name ($1)" 1>&2
  984. X                      return 1
  985. X                    fi
  986. X                fi
  987. X                [ "$FIELDS" ] && FIELDS="$FIELDS,"
  988. X                FIELDS="$FIELDS $OUTFIELD"
  989. X                if [ "$SUBSELECT" = "" ]
  990. X                then     [ ! "$PRINTF" ] && PRINTF="|"
  991. X                    WIDTH=`expr "$RESULT" : \
  992. X                        '[^    ]*    \(.*\)'`
  993. X                    PRINTF="$PRINTF%-$WIDTH.${WIDTH}s|"
  994. X                else    if [ ! "$AGGREGATE" ]
  995. X                    then    PRINTF="$PRINTF\\\"%s\\\" "
  996. X                    else    PRINTF="$PRINTF%s\n"
  997. X                    fi
  998. X                fi
  999. X                shift
  1000. X            fi
  1001. X        done
  1002. X        shift 2
  1003. X        WHERE=""
  1004. X        SORT=""
  1005. X        while [ $# -ne 0 ]
  1006. X        do    
  1007. X            if [ "X$1" = "Xwhere" ]
  1008. X            then
  1009. X                where "$@"
  1010. X                [ "$?" -ne 0 ] && return 1 
  1011. X                WHERE="$WHERE || NR == 1"
  1012. X                shift
  1013. X            elif [ "X$1" = "Xorder" ]
  1014. X            then     [ "X$2" != "Xby" ] && 
  1015. X                    echo "Syntax error ($2)" 1>&2 && 
  1016. X                    syntax select && return 1
  1017. X                shift 2
  1018. X                while [ $# -gt 0 -a "$1" != "union" ]
  1019. X                do
  1020. X                    if [     "X$1" != "Xasc" -a \
  1021. X                        "X$1" != "Xdesc" -a \
  1022. X                        "X$1" != "Xnum" ] 
  1023. X                    then    lookup_field "$1" 
  1024. X                        [ "$?" -ne 0 ] &&
  1025. X                echo "Bad field name ($1)" 1>&2 && return 1 
  1026. X                        [ "$SORT" = "" ] && 
  1027. X                            SORT="sort -t\"    \" "
  1028. X                        SORTL="`expr $OUTFIELDNUM - 1`"
  1029. X                        SORT="$SORT +$SORTL"
  1030. X                        [ "X$2" = "Xnum" ] && 
  1031. X                            SORT="${SORT}n"
  1032. X                        [ "X$2" = "Xdesc" ] && 
  1033. X                            SORT="${SORT}r"
  1034. X                        [ "X$3" = "Xdesc" ] && 
  1035. X                            SORT="${SORT}r"
  1036. X                        SORT="$SORT -$OUTFIELDNUM"
  1037. X                    fi
  1038. X                    shift
  1039. X                done
  1040. X            elif [ "X$1" = "Xunion" ]
  1041. X            then    shift
  1042. X                UNION="Y"
  1043. X                break
  1044. X            else    shift
  1045. X            fi
  1046. X        done
  1047. X        [ "$INAGG" ] && WHERE="NR == 1"
  1048. X
  1049. X        if [ "$DISTINCT" != "" ] 
  1050. X        then    if [ "$SORT" = "" ]
  1051. X            then    DIST="sort | uniq | tee /tmp/$$row"
  1052. X            else    DIST="uniq | tee /tmp/$$row"
  1053. X            fi
  1054. X        else    DIST="cat"
  1055. X        fi                    
  1056. X
  1057. X        TABLEFILE="$TABLE~"
  1058. X        [ "$SORT" != "" ] && cat $TABLE~ | eval "$SORT" > /tmp/$$ &&
  1059. X                            TABLEFILE="/tmp/$$"
  1060. X
  1061. X        if [ "$SUBSELECT" ]
  1062. X        then    awk -F"    " "$WHERE {printf \"$PRINTF\", $FIELDS }" \
  1063. X                            $TABLEFILE |eval "$DIST"
  1064. X        else    if [ ! "$QUIET" -o "$INAGG" = "Y" ]
  1065. X            then 
  1066. X            ( set X `cut -d\     -f1 $TABLE@` ; shift 
  1067. X              echo $NOCR1 "-$1-$NOCR2" ; shift 
  1068. X                for HEADING
  1069. X              do 
  1070. X                echo $NOCR1 "$TAB-$HEADING-$NOCR2" 
  1071. X               done ; echo "" )
  1072. X            fi |
  1073. X            awk -F"    " \
  1074. X            "$WHERE { cnt += 1 ; printf \"$PRINTF\\n\", $FIELDS }
  1075. X            END    { printf \"( %1d rows)\\n\", (cnt - 1) \
  1076. X            >\"/tmp/$$row\" }" - $TABLEFILE | eval "$DIST" \
  1077. X                && if [ "$DISTINCT" = "" ]
  1078. X                then    cat /tmp/$$row
  1079. X                else     X=`expr \`cat /tmp/$$row|wc -l\` - 1`
  1080. X                    echo '('$X' rows)' 
  1081. X                fi
  1082. X        fi
  1083. X    done
  1084. X    return 0
  1085. X}    
  1086. X
  1087. X#
  1088. X#**************************************************************************
  1089. X# main
  1090. X#**************************************************************************
  1091. Xwhile :
  1092. Xdo
  1093. X    while :
  1094. X    do
  1095. X        echo $NOCR1 "* $NOCR2"
  1096. X        read LINE || exit 
  1097. X        SQLPART="`expr "$LINE" : '\(..*\)/.$'`"
  1098. X        if [ "$SQLPART" != "" ]
  1099. X        then
  1100. X            [ "$NEW" = "Y" ] && _CMD=""
  1101. X            if [ "`expr "$LINE" : '.*/p/g$'`" -ne 0 ]
  1102. X            then
  1103. X                _CMD="$_CMD"`expr "$LINE" : '\(.*\)/p/g$'`"$NL"
  1104. X                LINE="/p/g"
  1105. X                NEW=""
  1106. X            else
  1107. X                _CMD="$_CMD""$SQLPART""$NL"
  1108. X                LINE="`expr "$LINE" : '.*\(/.\)$'`"
  1109. X                NEW=""
  1110. X            fi
  1111. X        fi
  1112. X         case "$LINE" in 
  1113. X            /p|p)  echo "$_CMD";;
  1114. X            /g|g)  break;;
  1115. X            /p/g|pg) echo "$_CMD" ; break ;;
  1116. X            /r|r)  echo "reset" ; _CMD="";;
  1117. X            /s|s)  umask $UMASK ; $SHELL ; umask 0000;;
  1118. X            /e|e)  umask $UMASK ; echo "$_CMD" > /tmp/$$
  1119. X                $EDITOR /tmp/$$; _CMD="`cat /tmp/$$`"
  1120. X                umask 0000;;
  1121. X            /i|i)  echo $NOCR1 "Enter include file: $NOCR2" 
  1122. X                read LINE  
  1123. X                [ -f "$LINE" ] && _CMD="$_CMD`cat $LINE`$NL" &&
  1124. X                echo "$LINE included";;
  1125. X            /w|w)  echo $NOCR1 "Enter output file: $NOCR2" 
  1126. X                read LINE  
  1127. X                [ "$LINE" ] && umask $UMASK && 
  1128. X                echo "$_CMD" > "$LINE" && umask 0000 && 
  1129. X                echo "$LINE written";;
  1130. X            /q|q)  exit 0;; 
  1131. X            \#*)     [ "$NEW" = "Y" ] && _CMD="" ;;
  1132. X            *)      [ "$NEW" = "Y" ] && _CMD=""
  1133. X                    _CMD="$_CMD$LINE$NL";;
  1134. X        esac
  1135. X        NEW=""
  1136. X    done
  1137. X
  1138. X    CMD=`echo "$_CMD" | sed \
  1139. X        -e "s/\'/\"/g" \
  1140. X        -e 's/\"\([^\"]*\)\"/\"\\\"\1\\\"\"/g' \
  1141. X        -e 's/\([<>!=][<>!=]*\)/ \1 /g' \
  1142. X        -e 's/</\\\</g' \
  1143. X        -e 's/>/\\\>/g' \
  1144. X        -e 's/\*/\\\*/g' \
  1145. X        -e 's/(/ \\\( /g' \
  1146. X        -e 's/)/ \\\) /g'`
  1147. X    [ ! "$CMD" ] && continue
  1148. X    IFS="$_IFS,"
  1149. X    eval set X $CMD
  1150. X    shift
  1151. X    IFS="$_IFS"
  1152. X    NEW="Y"
  1153. X    case $1 in
  1154. X        select)     select_ "$@";; 
  1155. X        create)     create "$@";;
  1156. X        delete)     delete "$@";;
  1157. X        drop)         drop "$@";;
  1158. X        insert)     insert "$@";;
  1159. X        update)     update "$@";;
  1160. X        edit)        [ "$2" ] && $EDITOR $2@;;
  1161. X        help)        help "$@";;
  1162. X        print)        select_ "select" '*' "from" "$2";;
  1163. X        *)         echo "Missing or unrecognized command." 1>&2 ;;
  1164. X    esac
  1165. Xdone
  1166. X
  1167. END_OF_FILE
  1168.   if test 20449 -ne `wc -c <'shql'`; then
  1169.     echo shar: \"'shql'\" unpacked with wrong size!
  1170.   fi
  1171.   chmod +x 'shql'
  1172.   # end of 'shql'
  1173. fi
  1174. echo shar: End of archive 1 \(of 1\).
  1175. cp /dev/null ark1isdone
  1176. MISSING=""
  1177. for I in 1 ; do
  1178.     if test ! -f ark${I}isdone ; then
  1179.     MISSING="${MISSING} ${I}"
  1180.     fi
  1181. done
  1182. if test "${MISSING}" = "" ; then
  1183.     echo You have the archive.
  1184.     rm -f ark[1-9]isdone
  1185. else
  1186.     echo You still must unpack the following archives:
  1187.     echo "        " ${MISSING}
  1188. fi
  1189. exit 0
  1190. exit 0 # Just in case...
  1191.