# COHERENT /rdb Relational Database Manager
*Mark Williams Company, 1992.* Text per OCR (tesseract) aus dem Scan, nicht korrigiert: Tabulatoren fehlen, Tabellen und Zeichen können falsch sein. Im Zweifel gilt der Scan. Dieses Dokument entsteht aus `doc/handbuch.txt` mit `tools/handbuch_md.rb`; Änderungen gehören dorthin oder in den Konverter.
*— PDF-Seite 1 —*
```text
COHERENT
[rd Relational
Database
Manager
```
*— PDF-Seite 2 —*
```text
Copyright © 1992 by Mark Williams Company.
Copyright © 1992 by Revolutionary Software, Inc.
All rights reserved.
This publication conveys information that is the property of Mark Williams Company and
Revolutionary Software, Inc. It shall not be copied, reproduced or duplicated in whole or in
part without the express written permission of Mark Williams Company and Revolutionary
Software, Inc. Mark Williams Company and Revolutionary Software, Inc. make no warranty of
any kind with respect to this material and disclaim any implied warranties of merchantability
or fitness for any particular purpose.
COHERENT is a trademark of Mark Williams Company. /rdb and /act are trademarks of Rod
Manis. UNIX is a trademark of AT&T. MS-DOS is a trademark of Microsoft Corporation.
dBASE is a trademark of Ashton-Tate. All other products are trademarks or registered
trademarks of the respective holders.
Revision 1 Printing54321
Published by Mark Williams Company. 60 Revere Drive. Northbrook, Illinois 60062.
E-mail: uunet!mwe!support (Technical Support)
support@mwc.com
uunet!mwe!sales (General Information)
sales@mwe.com
BIX: join mwce
CompuServ: 76256 .427
This manual was written under the COHERENT operating system, using the MicroEMACS and
ed text editors. Text formatting was performed by the COHERENT edition of the troff text
formatter, using its PostScript output function. Typesetting of this manual, from the table of
contents through the index, was performed by one script written in the COHERENT Korn
shell. Camera-ready copy was printed on a Hewlett-Packard LaserJet IIP printer using the
Pacific Page PostScript cartridge.
Printed in the U.S.A.
```
*— PDF-Seite 3 —*
```text
Table of Contents
Le Introductions occ eo ob ira oo 0 eetaa © ww wees © wo where ee 8 oe meee oe 1
Installing /rdb. «6 6. ee ee ee ee te ee 1
European Keyboards... . 2... 0. eee eee 1
Data Bases and COHERENT ....-- eee eee eerie 2
Tables and COHERENT... ...-----+ eee 2
Operating Systems that Support COHERENT-Style Environments 3
Applications Development... 6.6 6s eee ee ee ee ee ee ee eee 3
Data Bases nici css sieves oo aeons % & 8 Ewe 3
COHERENT Environment . . 3
Fourth Generation Systems . 4
Attempts at a Definition . . . 4
Previous Generations. ....... 4
Data Structures in the Data... . 5
A Revolution in Computing... .- 6
A Paradigm. .....+-+++ee% 7
The'Shell:. 2 & &ssasers w @ & anaes oe KieKEHO A 6 w MEK @ gw exer we Oe eS Se 8
Shell Operators ©... eee ee ee et ee eee ee ee ee ee te 9
Compatibility with MS-DOS 9
Conclusions 2 «sieves io oo vreceveie eae eyeuere @ e easseg ew 6 SRS Oe Le 9
2. Relational Data Bases . ll
FileSooi.6 3 6 6 atin ll
COMMIS. 5 wren te ee Hotes ee EELS STF HT. S 12
ROWS 655 6 6 8 Eh aSH aD % BH Wistar, < HwIANA Sw oe EELS 12
Columns and Rows... 2-6 essences 13
Shell Programming and Flat ASCII Files ..... 13
Listes 6 6 Fo Gases & we eC ww SHEEN @ 14
REVIEW, can so a 8 sires ng me meee © 8 ewes 14
Normal Relations ..... 2... +e see ee eee eee 14
How Is Information Accessed? .......+++-5 ena DS
Selected /rdb Commands........... Paro at) vx o LS
Creating Tables and Entering Data ........ oe 17
REPOrts 6 5 eye nen en oe eerece eo eres av 1B
The Big Text Field Problem 19
Non-Text Data Structures...... a 2 7.20
Large Tables... 1-21 ee eee +. .20
Architectural Performance Enhancements . . .
SOE wieseiceie 9.0 oieicece fe 8 scene 8 eo roe Par
Fifth-Generation Systems .. 2... ee ce ee eee eee ee ee ee eee
References). cx acacese iw oo ¥) siete © © of qoene & © BmKereTe wm chee ee we esecere |e 8 EE
3. Commands,I/O, Pipes .......-.
compute: Compute a New Result. .
justify: Align Columns........-
total: Compute Arithmetic Totals. .
subtotal: Compute a Subtotal .. .
Quoting Commands ........-.
PHOS: 6s bo wo Sees ww Fae. a we Guar
Syntax: How To Enter Commands Correctly... 2.1 ee eee ee ee eee tees 32
```
*— PDF-Seite 4 —*
```text
ii_ The COHERENT System
COHERENT Shell Scripts 2 sk sssarecn 6 6 sais wv % SOMERS © & Ba
Report Writing.........
Conclusion... ....6.0%
4. Entering Data into Tables . .
ver The: Forms: Rditor'vys'5 6 3 6 sie) 6 SF Mei BT G Retid 2 wo
enter: Mass Entry of Data.........
update: Updatea Table ....
Programs and Other Formats
Rules for Table and List File Set up . . .
Table Format .... 636 swe es
List Format .............
Tab Problems ............ eee
Seeing the: Tabs... os wiecsi9ve 2% eoeweneis © 6 MeeUNe wae 6
Table-Width Problems
Special Characters ies» «i pvsarsi ao, aware Hw ecaKenD WH Mi tH
Data Validation: How To Get Data Right
5. ve Form and Screen Editor
ve Commands...............
Moving Around............
Displaying Your Data
Getting the Right Row... . 2.6... eee eee ee eee
Inserting Text. sk wire so SF WWE FOE SRK TR He
Deleting TERE: wm gions oe ee SwtEWES & & Shai AH SENG & A EMM | 4 ERS
Targets 6. eee eee tee e eee eee eee eae
For Your Information
WEEN E ROWS: 5 6, esac. Se 6 PUT BD WSO FF Eels = » 0: exerayee © om eve
Getting Back to COHERENT
Quit Commands. .........
Colon Commands
MACKOS! 4 !95.5 3 5 THESES FF Filan wo o ee
FUCOpUONS
*— PDF-Seite 5 —*
```text
The COHERENT System iii
Column INnchasiONs; «ssi ee 6 acess 16 ww aiwIENd © Sw ATRL Le w HH wKMLRLE ew oe EEE 61
Multi-User Considerations. .. 6.6... eee eee tee eee eee eens 62
/rdb-ve Compatibility
Limits. .....-.4-
ve Validation. ....
Control-Key Mapping
Command-line Options
Screen Size and Column Limits . 2... ee ee ee ee ee eee eee 70
User Column in Audit Files... 26 6. ee ee ee eee 70
Fast-Access Indexing From ve . 6.6... eee ee ee ee ee ee eee 70
What Is the Cost of Indexed Searching?. .. 6.66 eee ee ee ee ee eee 70
6. Data-Base Design... 6 66. ee ee ee eee ee eee 73
One-to-One Relationships in One Table. 2... 6 6 ee ee ee ee ee ee 73
One-to-Many Relationships in Two Tables ...........--
Many-to-many Relationships in Three Tables .. 1.6. eee eee ee ee eee 74
Planning i csiciais 6 a 8 & sense is ew stares le we ebiewene © eo
Normalization 0:0 16 6 0 6) cceceneie oe senses ee 8
Functional Dependency .........++++
KeyS ss. ccsssiers 6 & & steven end % ¥ weuelare & & ®
Universal Relation .......+ ++ eee eee
Redundancy Problems. ..........++5
Update Problems .........-++e20+5
Insert and Delete Problems
First Normal Form .........-.
Second Normal Form.........
Third Normal Form.........-
Normalizing Example........-
Complex Queries with Joins .......
Pipeline Join... . 2. eee ee eee ene
tmpl
tmp2 ..
tmp3
Phone Book ....-+-++esee05%
7. Shell Programming. ... 1... ee ee eee ee eee
Data-Base Programming in COHERENT Shell Language... ... 6. +s eee ee ee eeee 87
COHERENT Utilities 4 ¢ & siscavars w ale aymcais we oi SiaaeS wow H EINREe a ww MANES HH slwie
awk: Language to Produce Complex Reports .
cat: Display a Table or List File
echo: RepeataStatement......
grep: Find All Rows That Contain a Given String ... 1-6 eee ee eee ee ees 88
od -c: Octal Dump All Bytes as Characters 88
sed: Stream Editor to Edit Fileina Pipe ...
sh: COHERENT Shell Programming Language
spell: Check Spelling in a Table or List File
tail: Display Bottom Rows of a Table or List File... 2... 6. ee ee ee ee eee 89
we: Word Count. 666i 6 oe ee biel eo 8 be ee oe ee ee ee wee ee ow eee 89
Text Editor to Enter and Update Files... 1... ee eee ee ee ee eee ee eee 89
Reading and Writing Data Base Files .. 6.61 eee ee te ee ee ee 90
Parsing ROWS 0.660 tet ee eee ee ee ee Hee eee ee ee Hee 91
Tables to Shell Variables... .. 2... 22-22 ee eee ee ee ee ee 91
Liste to Shell Variables: & Geciieis 6 easels FHT SH Ere Ae wae ww eH aNEK 93
Report Writing. 2... ee ee ee ee ee eee ee eee eee eee 94
8. Shell Menus . 2... cee ee ee eee ee eee eee meee eee ee ee 97
CONTENTS
```
*— PDF-Seite 6 —*
```text
iv_The COHERENT System
Example Shell Menu Programs... oo srecece 9 9 eieiee © se ere we eR ee
CBS@ACHIONG & wxgcses a ow siereraie % H SETS SE
termput and tput Commands. ............
clear Commiandisjais 2s 5 BGs © OE PaNeals % HS
etirsor Commmianid:.... 2 6 « cieceere so saeras © & &
9. Tablesand Forms......
Building a Screen Form .
10. Fast-Access Methods. ..... 6... 0... eee eee eee
APPIOpelnte: Use si. 6 x sh 45S aes A SWISS Bd EL MOIS 4 HE MOTE W FE EME Me oe
The indexand search Commands. cceseice ce 6 0 eee © w & ware cd @ wo BNALENG wa % Bas
Searching oii 6 6 oasis & 6 FE HSS © FH Shetele o o eSessie oe eseree es ew me
IRTELACH VO hes a6 5 sarees mF BACAR Be WIG |S TAO 6 BG ROO GH OID ve
Pipe Key . 2... eee eee ee ee ees 0
File Inputiveis 6 & 2 isa 6 4 WG Sie SK © PAGO SS Gwe ews Ts: Fowlers ote 9 ove
File: Input by Pipes oe ois 6 ie «sca ee .
Multi-Rows, Multi-Columns, and Multi-Key:
Methods of Searching
Sequential... 2... . ee eee ee eee
Record vicscs eso scare as Hae’ we BG
Inverted or Indexed Sequential. ..............
Partial Inital Match
Analysis .........
Managements i 5 5.5 aileisies & & EWS 8 & Rlecene © om exe
11. Miscellaneous Commands. .................54.
Record Locking: One ata Time... . 2.2.2... ee eee
Finding What to Lock .....
lock and unlock. ........
Blankinga Record .......
Dates: Conversion and Arithmetic .
Julian and Gregorian... .. .
DiferenCe: x 6 wanais sa eo ees
Formats .. 1... eee eee eee eee
Conversions 6 60s 6 ob 6 ORK HE Tas
Set-TheoryCommands.............05.
Concatenating Tables ...........02000 ee
Subtract One Table From Another
Intersect Between Tables ...........000005
12. Combining /rdb with COHERENT. ..............
Multi-User Concurrent Access to Files ..........
BaGkUp.. - ooo seis % @ Serres
Checkpoint and Recovery
VAHGAYOR «6 a creas 6 6 & BHR 4 KH aTENS
AUG TYAS ANG LOCLIE so: en esnrcece 19 e SMROONS © & HORIALS te @ & TKEMENOND SFE WemNON | YF
13. Other Data-Base Systems................00.
RESOULCOUBE) onerere ie co 9 ercasioreie la ANOLE Me ew eREIEOIE
C Programming Unnecessary. ............0005
SPEEG:. x 5 a KMO @ SW RUeIOVENS wT SHRURE @ HO HaTGNSNS
Size
CONTENTS
```
*— PDF-Seite 7 —*
```text
The COHERENT System _v
14. Can You Say that in English? . 0.0.66 ce eee ee eee eee ee ewe ne
Data-Base Models... .......++4-
Entity-Relationship..........
BIMMry <2 o prexenens 2 9 sieiee
Semantic Network ..........
Infological ......-++..+05-
PROLOG: Programming in Logic
The Grand Unified Field Theory of Information ..........
15. PROLOG and AL. 6 og ceceie 6 oo eeiene ee 0 eneene
PROLOG Language and Environment . .
Predicate Calculus
Facts ....5 e806
Questions
Rela w.. ee 2 saemeseune & & eieeeis
/rdb Interface to PROLOG. ........
tabletofact . . oicecoce es a6 speveses
tabletorule’. ¢ 5 osi)n 6 be ees
Problems of PROLOG. ..........++
searchtree: Data-Base Tree Searching. .
16. /rdband Co. wc e ce ees
Don't Do Nto:5 sc wsaravereyps we ierserve 6 & Hwreners
system(): Tell Shell to Execute a Program ......-..----
execl(): Execute a Call sccsie bb Seis 6 6 ein ea eee
execl() Shell Programs ..........+
fork(): Create a Child Process.
PIPES! s nyeeses woe w veers & TREES
One-Way Pipe.......+-+-+-++-
Pipe to Standard Input........
Two-Way Pipe .......+-++46-
Programming Style..........+..-
Fast Acceae! jc 2 oe vies © 0.8 HG © ©) HOKE we Chere
tabletostruct: Convert a Table toaC struct ..........4.-
Read Table into Memory: getfile() and fsize() ............
/rdb Functions: librdb.a.... . 6 6 ees ce eee nee nes
Colroutines: 6.1 ee ee Sie ees
Display Example ........--204-
Debugging... - 21. eee ee ee eee ee eens
Fast-Access Example
17. Manual Pages . 0... 1 eee eee eee eee renner ene
accounting termS . 6. 6 eee eee ee ee ee ee ee ee
List all /act commands .......
Addacolumn toatable........
Create adjusted trial balance table
Add a row to a table and update index tables .......... 172
Return the ASCII value ofa character... .....-.-.--- 174
RAN HTH SETNETHIE Ge MaNEENS @ CM METER A ORIENT Ww @ & NUS SHE MW SO SoM Ow & 176
Create balance sheet from adjusted trial balance ........ 176
Replace all data in a record with spaces. ............-- 177
Produce bill-of-materials from parts list............-- 178
Post payroll to ledgerpay... 1... eee eee eee eee 180
CONTENTS
```
*— PDF-Seite 8 —*
```text
vi_The COHERENT System
calculate... ......0. Compute each tax form listed. ...........
CAD servis % & ERLE BS 8 Convert first letter of each word to upper case. .
SABHMOW 0 sw « siterexers & © Compute balance column of cash table........
chartdup.. . 6 6 6s i 8 6 Check for duplicate names and accounts in chart.
CReckrdb: cs snvcxe ws 3 Report any rows in which columns do not match head line . . 184
Chr... . eee ee eee eee Display the character corresponding to a number
ClearsrdDis 6 & ssieie's 6 8 Clear the terminal's screen .. 2... 2... eee ee eee
WSC irae a 0 & sxeneree a 6 Close accounting period creating journal for next
column..... display columns ofa table in anyorder..............
commands Describe /rdb commands... .......0. 000000 eee
compresss .. . - Squeeze out all leading and trailing blanks............
compute .... - Calculate columns ofatable ...............00005
computedate Add given number of days toadate............000-
consolidate. i ..06. 668s Combine all subsidiary journals to general journal... .... 195
Cpdirsrdb:. «cessor s & os Copy one directory tree to another directory .
catate. 6 bev e cee Produce customer statement ............. 000000
CUFBOR. 6k canes 6 6 2 8s Move the cursor to the row and column requested
CMS ME. ecsssysie ie on 6 suiniee a) ai» semanas Gee evanaa % ow alerts Bie Ey é
Gatatype & concis 6 6 8 86 Display the data type of each column selected .
Print a data-base dictionary. ...........0.000 eee
Blank record and update index file... ..........000%
Output table of rows that are in only one table ......... 205
Write table or list file to standard output. ............ 206
Display invalid values inacolumn..............0.05 207
OMber! 5 i SS So, gece Add rows to a table or list file without an editor......... 209
Oxplode ix sais 6 se Kavos Produce table of subparts and their count fora part. ..... 212
:(: ie Test for functional dependency of columns. ........... 214
filesize Return the number of characters ina file............. 215
fillform Fill a tax from with adjusted trial balancedata ......... 216
fixtotable Converts fixed length format to /rdb table format. ....... 216
fOOE 6: 5 ces Foot or subtotal Debits and Credit of ledger ........... 217
getjournal . Copy journals for sales, purchasing, pay systems. ....... 219
gregorian. .. Convert column of dates for arithmetic and format change .. 219
hashkey ... Return the hash offset for key strings. .....
head lineisia< % & 5 NGOS % yo: enessuere of e ciquecs WIE wreckaie h dierarausland tao suaeuacs
Head ecsie se & w acersrars Remove an /rdb head from both table and list files
headon...........- Add an /rdb header toatable .............04.
helpme esas 2 6 & g'siele es & List the help commands available ..............
howmany........... Display the number of commands in a directory... .. .
INdOK i555 eS NaN. Setup table for search. cee 6, severe ws eomarsvnrd
insertdash.......... Insert dash line as second line intable...........
intersect . 265i eee Write table of rows that are in both input tables...... .
MVOME as as Brees a 8 Print invoice fora sale order ...........00 0000s .
jointable . 2. ieee cas Join two tables into one where keys match............
jullaniss s 2 is eee ese Convert column of dates for arithmetic and format change . . 234
SUBHHEY oy. ce cee vicauenene - Left or right justify the columns ofatable ............
label... ... 204. - Print mailing labels from a mailinglist ....... .
Tengtlh. «x 6 &: sissavas - Return the length of its argument or input file
dk ee - Print form letters from a mailing list............
like ... : Find names that sound like anothername........
listtosh . Convert list format to shell variable............ rare
listtotable. Convert from list to table format... ...........0005
CONTENTS
```
*— PDF-Seite 9 —*
```text
The COHERENT System _ vii
LOCK. i a &. siarerers wo 6 wos Lock a record or field ofa file... 6.6... . eee ee eee ee
lowercase. Transform text to lowercase ............4- ete
maximum Display the maximum value in acolumn..... .
mean... Display the meanofacolumn ............-
menu... Root menu with some COHERENT commands... . .
minimum. Display the minimum of each column selected .. . .
not..... Logical not, to reverse return status of command. . .
number Insert a column-row number into a table or list. . . .
Number Insert a column-row number into a table or list. . . .
pad .... Add extra spaces at end oflastcolumn.........
padstring. Return string with blanks to filla field .......
paste.rdb. Paste together two or more tables ..........
path.... Find the full path ofacommand...........
precision . Display the precision ofacolumn .......... seein
project .. Write selected projects (same as column). .........++.
prompt. . Echo a string on the standard output. .............-.
FAD.» ws List all /rdb programs in directory SRDB/bin . . .
record. . . Find and output a record froma table. .......
rename. . RENAMEACOMUNG§: 02054 © 8 cies sw HIKE ©
replace . . Insert a record into a file at specified location . . .
FEPOLls sc ovens wo & we Write reports using a form andatable .......
reportwriter......... Sample program to write standard reports .... .
rmblank: 5 sss. 6 5 se Remove blank rows fromatable...........
rmcore . . Remiove all Core fi1ES 0.0/5 5 « o) ceisiere a 0) 06 oceans oe of 8, eee
row .... Make a new table where rows match logical condition . .. . . 266
sale.... Enter sale order, and item, update customer. ..........
schema. . Print a table's schema ............-+255
screen. . . Convert a form into a screen-input shell program.
search. . . Search a table. « «.cevee = ¢ x ewes 2 HO waRw~ 2
searchtree Seek a string node in tree table... . 2.6... 6 ee ee ee eee
SOG: is ke oe ew Display nonprinting as well as printing characters
seek..... Return the beginning and ending offset of a row. .
select.... Output selected rows... 22 6 ee ei ress
SOTHABle 5 ica oe 6 aK8 Sort a table by one or more columns ........-..-0000%
SOUNKEK: § i665 FS FFs Convert a name into soundex code... ......--++0005
splittable . . Divide a table horizontally... ..........-..
substitute . Replace old string with new string. .........
subtotals 5 caowa ss ss Fe Output subtotals of columns inatable..............
NADICOFIBE, cece se wo eons Report whether a file has table or list format. ..........
tabletofact.......... Converts a table to PROLOG fact-file format . . .
tabletofix........... Convert /rdb table format to fixed-length format
FADIStOHAE,. 0 erence 2 ce 95 cnexe Convert a table to list format... .........-
tabletom4 .......... Convert a table to m4 define-file format... .. .
tabletorulle ...:0:5 60 6 see Convert a table to PROLOG rule-file format. . . .
tabletosed .......... Convert table format to sed file format ......
tabletostruct......... Convert table to C-language struct declaration .........
tabletothl ...0 oie eo ones Convert /rdb table format to UNIX tbl/nroff format. ...... 296
tax. «55 Compute tax from income and tax table ............. 296
termput. Get terminal capability from /etc/termcapfile.......... 297
testalls 6. is224 8 5 5 8 BER Test all /rdb programs in directory SRDB/demo ........ 299
testseareht crc 6 6 6 & czars Test the fast-access methods ........0 2.0.5 00 eeu ee 299
timesearch.......... Time fast-access methods... ....... 00005 eee eeee 299
todaysdate.......... Print today’s date in YYMMDD format............... 300
CONTENTS
```
*— PDF-Seite 10 —*
```text
vili_ The COHERENT System
UNION. ws ee ese erees
uniondict. .
update.inv.... 0 sees
CONTENTS
Sum:accolumns & 8652,4 6 6 i608 6 Biecetes 2
Word-for-word substitution using a translation fille.......
Trim excess white space fromatable.......
Remove leading and trailing blanks from a string
Fetch termcap entry for a terminal type..... .
Concatenate tables... 2... ese eee eceee
. Combine three tables into translation dictionary
. Unlock a record or field ofafile...........
Multi-user update with screen form and record locking .. . .
Display and edit records in any sized file. ....
Convert input to all upper-case characters... .
Find invalid data... .seccecervenece
Visually editatable....... ee eee eee
Lock a table before editing, unlock afterward.
Create and display ve look-up tables .......
Display the command description and syntax . .
Display commands with functions in description
Output the width of the widest entries in a table
Display the width ofeachcolumn .........
. Convert text file into list of unique words. ... .
```
*— PDF-Seite 11 · Buchseite 1 —*
# Section 1 — Introduction
/rdb is a relational data-base management system for COHERENT, MS-DOS. UNIX, and other operating systems. It is designed to use the full power of the COHERENT shell and supplemental tools, including awk, sed, and the C language.
With /rdb, you can implement a full-featured relational data base, including a menu-driven data input and a report writer. Also, because large portions of /rdb are written in the shell and related COHERENT tools, /rdb serves as an excellent tutorial in learning how to use the full power of COHERENT.
## Installing /rdb
To install /rdb, log in as the superuser root. Then cd to the directory in which you want /rdb to live, say /usr. Then use the COHERENT command install to install the program. install has the following syntax: install version device disks, where version is the version number of the program being installed, device is the floppy-disk drive from which the program will be installed, and disks is the number of disks that compose the installation.
The version number appears on your /rdb manual. The number of disks is one. If you are installing from a high-density 5.25-inch floppy disk in drive O (drive A), device is /dev/rhaO; if you are installing from a 3.5-inch floppy disk in drive 1 (drive B), then device is /dev/fval. See the COHERENT Lexicon entry for floppy disks for a table of disk sizes and devices.
For example, if you are installing version 2.0 from a 3,5-inch disk in drive 0, use the command:
```text
/etc/install 2.0 /dev/fva0 1
```
COHERENT will take care of the rest.
Be sure to edit your .profile to include the directory $RDB/bin. where SRDB is the directory into which you installed /rdb. For example, if your .profile the PATH variable as follows:
```text
PATH=/usr/bin:/bin:$HOME/bin:.
```
and you have installed /rdb into directory /usr/rdb (which is the default), then you should edit your PATH statement to read as follows:
```text
PATH=/usr/bin: /bin:/usr/rdb/bin:$HOME/bin:.
```
## European Keyboards
COHERENT version 3.2 lets you install any number of predefined keyboard definitions into your keyboard driver. These let COHERENT support the keyboard layouts and national character sets for most European countries.
If you are using /rdb with one of COHERENT's European-ized keyboard definitions, you must rework three programs. These programs are the table editors ve and jve, and vindex, ve's hash indexer. The European versions of these programs are located in directory
*— PDF-Seite 12 · Buchseite 2 —*
SRDB/europe.
To use them in place of the default US keyboard versions, put the path $RDB/europe before $RDB/bin in your PATH variable. For example, if /rdb’s home directory is /usr/rdb, then insert the following entry into your .profile file:
```text
export PATH=:/usr/rdb/europe:/usr/rdb/bin: "$PATH"
```
Or you can simply replace the US versions with the European ones:
```text
ed /usr/rdb
mv ./europe/* ./bin
```
A side effect of the European versions of these programs is that characters that exceed the decimal value of 127 are highlighted. In other words, characters such as umlauted and accented vowels, tilded n’s. currency symbols, etc., will be highlighted in the screen displays for ve, jve, and vindex. To suppress highlighting of eight-bit characters, make a new entry in your /etc/termcap file by copying the entire description for your terminal type and deleting the so (or standout) and us (or underscore) entries, up to and including the ':". For example, the following copies the termcap entry ansipc, modifies it for European use, and makes it into a new termcap entry called an-e. The portions in boldface are deleted:
```text
ap-e|ansipc-eur|ansipc for european kbs: \
tal=\E[L:am:bs:bt=\E[Z:bw:cd=\E[0:ce=\E[K:ch=\E[$%i8d‘:cl=\E[20:\
rom=\E[%itd; $dH:co#80:cs=\E[%itd;tdr:cv=\E[%itdd:dl=\E[Msho=\E[H:\
:kO=\E[Ox:k1=\E[1x:k2=\E[2x:k3=\E[3x:k4=\E[4x:\
tk5=\E[(5x:k6=\E[6x:k7=\E[7x:k8=\E[ 8x:k9=\E[9x:\
tkb=*h:kd=\E[(B:kh=\E[(H:kl=\E[D:kr=\E[C:ku=\E[A:\
:1i#24:11l=\E[24;1H:hd=\E[C:se=\E[(m:sf=\E[S:sg#0:so=\E[7m:sr=\E[T: \
:te=\Ec:ue=\E[m:up=\E[A:us=\E[4m:\
+KI=\E (5x: KD=\E[3x:Kd=\E[P:KB=\E[6x:KU=\E[4x:Ku=\E[@:KM=\E[7x:KJ=\E[8x:\
:Kt=\E[Z:KT=\t:KL=\E[ 1x: KR=\E[2x:KP=\E[(U:Kp=\E[V:KX=\E[9x:KC=\E[0x:\
+KE=\E[24H:KW=*F :Kw=“R:Kr=“N:do=\E[B:
```
Once you have installed the new termcap entry, set your TERM variable in your .profile to your new termcap entry:
```text
export TERM=ap-e
```
## Data Bases and COHERENT
There are two fundamental ideas that are necessary for application development in a COHERENT environment. One is the relational model. which allows you to see all applications as simple operations on tables. The other is the idea of using COHERENT tools to pass data through pipelines and filter programs. instead of traditional programming.
## Tables and COHERENT
First, we will introduce you to tables. All information can be entered into and manipulated in tables. This is the fundamental idea of relational data bases. The COHERENT system itself provides a rich and varied environment in which tables can be manipulated. After covering basic operations, you'll see simple data-base design principles. Then you will learn how to use COHERENT tools. You will also be introduced to advanced data-base problems and solutions. There are a number of examples illustrating common data-base problems and solutions, and a model business operation and accounting-system tutorial and manual is included as a case study. Finally, all the manual pages are appended.
*— PDF-Seite 13 · Buchseite 3 —*
## Operating Systems that Support COHERENT-Style Environments
By the COHERENT environment, we mean file redirection. pipes. and COHERENT-style tools like awk, grep, and sed. This environment can be on a computer running COHERENT, any of the various flavors of COHERENT, or MS-DOS with UNIX tools added.
## Applications Development
When a person uses a computer in his work, he usually needs to have it programmed for his particular application. A scientist might study the data from his experiment, an entry clerk takes orders or reservations, a business person manges his business, an accountant prepares financial statements and tax forms, a lawyer does research and prepare briefs, and so forth. Some users can develop their own applications with COHERENT tools themselves. But most users need to have computer professionals set up applications for them. In this case, the power of the COHERENT environment eases the job of the developers and extends what can be done.
## Data Bases
Almost all applications require some form of data base. Typically, a data-base management system is a computer program that maintains data and performs tasks such as easing the input and validation of data, finding data, computation and transformation of data, reporting, and so forth.
## COHERENT Environment
The COHERENT system is not just an operating system. It has hundreds of programs that work together to do most of the common computer jobs. COHERENT tools provide an entire support environment for software application development and operation. It does so much of the work, that the jobs of both the developer and the user are enormously simplified. But since this environment is new to the computer profession, it is seldom used to its maximum potential. Often, developers don't know how to do on the COHERENT system many of the things they are used to doing on other systems. Frequently, developers do things in the COHERENT environment in difficult or slow ways that could be done much better if they knew how.
Many data base systems are now available on the market. But almost all are software prisons that you must get into and leave the power of COHERENT behind. Most were developed on operating systems other than UNIX or COHERENT. Consequently, their developers had very few software features to build upon, and wrote the functionality they needed directly, without regard for the features provided by the operating system. The resulting data base systems are large, complex programs that degrade total system performance, especially when they are run in a multi-user environment.
COHERENT provides hundreds of programs that can be piped together to easily perform almost any function imaginable. Nothing comes close to providing the functions that come standard with COHERENT. Programs and philosophies carried over from other systems put walls between the user and COHERENT, and the power of COHERENT is thrown away.
The shell, extended with a few relational operators, is the fourth-generation language most appropriate to the COHERENT environment.
*— PDF-Seite 14 · Buchseite 4 —*
Introduction
## Fourth Generation Systems
In recent years, a variety of developments in programming language design have emerged. Object-oriented languages are becoming common, and languages explicitly supporting multiple tasks and inter-task communication are also gaining popularity. Unfortunately, these efforts have resulted in productivity increases too small to offset the growth in the size and complexity of software systems. A response to this has been the development of fourthgeneration programming languages. Although not commonly thought of as such, the COHERENT shell is one of the most powerful and flexible fourth-generation languages available.
## Attempts at a Definition
There is no consensus on the definition of what constitutes a third- or fourth-generation language. Mainstream third-generation languages are typed, procedural languages. They are standardized and largely hardware independent. Operations in the language must be specified in a detailed. step-by-step algorithmic fashion. Third-generation languages do very little implicit processing. Third-generation languages are general purpose, even most of those that were ostensibly designed as special purpose languages.
Fourth-generation languages are usually intended as design tools for a particular application domains. They are usually free form in their use of variables, often not requiring type definitions and allowing dynamic typing of variables. They don't emphasize a modular, procedure-based style of coding. Instead, they contain a number of predefined procedures for performing various high-level operations. The high-level operations involve large amounts of implied processing. For example, a “sort” operator is usually available. The facilities of a fourth-generation language are usually both more powerful and less flexible than the facilities available in a third-generation language.
A fourth-generation programming language (4GL) should let you simply write what it is you want, rather than a detailed procedure of how to produce it. Although many products call themselves 4GLs today, they are mostly rewrites of COBOL and report writers. They are too low level and tedious. This is definitely not what a 4GL should be.
## Previous Generations
The first generation of computer languages was the sequence of zeroes and ones that were the machine instructions. In the beginning people had to code in this way.
The second generation was “assembly language,” which has a one-to-one correspondence with machine instructions. For example, this assembly-language code adds register 1 to register 2:
```text
add rl,r2
```
One line of code produced one computer instruction. Then, in about 1956, FORTRAN was written to do formula translation, and it became much easier to write programs. Each line of code produced several computer instructions. The third generation has come to encompass sophisticated macro assembly languages, and other so-called high-level languages like C, COBOL, Pascal, LISP, PL/1, and many others. There are advanced constructs close to English like if, then, and else, but the types of statements are constrained to mostly arithmetical operations, with limited string capabilities. A typical third generation program consists of statements like:
*— PDF-Seite 15 · Buchseite 5 —*
```text
for i=1 to 10
print i, sqrt(i)
next i
```
The next step comes in describing what you want and letting the computer figure how to give it to you. The fourth-generation has English-like words, but statements typically deal with more than numbers, and are “non-procedural.” A fourth-generation environment, for example, reduces a program to sort all the lines in a file to:
```text
sort file
```
Fourth-generation language primitives often include relational operators, while thirdgeneration languages generally do not. And, when you need to mix procedural with nonprocedural instructions, that is easy to do. For example:
```text
for file in filel file2 file3
do
```
```text
sort $file
done
```
At the COHERENT shell level, you can in many cases say what you want without saying how (non-procedural), and you will get it. For example, type the command
```text
sort file
in the the COHERENT shell and you get a sorted file. Or, type
spell file
```
and you get a list of words in your file that are not in the dictionary. One line of commands calls one or more programs, each of which may have thousands of instructions.
With the shell, you can put together an application in minutes or hours, instead of the weeks or months required with 3GL code. In a 4GL, you should be able to write most applications in a line or two. With the shell, you can say things like:
```text
column Account Amount Description < file |
grep expenses |
```
```text
sort |
```
```text
lpr
```
This short program extracts some of the columns in a file, pipes them through another program to select the rows that contain the string expenses, sorts the selected strings, and prints them.
This same report would take tens to hundreds of lines in COBOL, PL/I, C, and most commercial 4GLs. In those languages. you write instructions one at a time, to process records from the file one at a time. This is very tedious compared to writing one instruction to operate on the entire file.
## Data Structures in the Data
In an ideal environment, the structure of data is in the data. Newline-separators for records and column-separators for fields can tell any program where the fields and records are. 3GL languages must have the data structure hard-coded into them, so that a program can read only one kind of file.
*— PDF-Seite 16 · Buchseite 6 —*
Introduction
In a traditional third-generation environment, the structure of the file must be hard coded into the program. In a fourth-generation environment, files have their structure embedded with newline and tab record and field separators. Any program can find a record by just looking at the stream of characters. Add a single character to the data file read by a COBOL program and all is changed or lost, so you must do file conversions in the COBOL environment all of the time. And these are done in COBOL. Any changes require that you edit and recompile all of the programs that read that file.
In addition, there are no file operators in 3GLs, only field-at-a-time instructions. Therefore. you must write loops to process each record. This takes much more code than just processing a whole file at a time.
Most commercial 4GLs are very similar to COBOL. You still have to do record-at-a-time processing. If the COBOL program takes 100 lines, the 4GL will take anywhere from 50 to 100 lines, to do what we did above in one pipeline.
## A Revolution in Computing
If you write C programs on COHERENT, you miss most of the advantages of shell-level programming. It's been suggested that since C and other languages on COHERENT give you the system() function call, this converts them into 4GLs. This is equivalent to saying that assembler is a 4GL if it has a system() function. But on non-COHERENT operating systems like MS-DOS and VMS, there is not as rich a variety of tools available as in COHERENT, except to the extent that COHERENT has influenced these systems.
The COHERENT system itself offers an integral tree index approach to data organization: the hierarchical file system itself. Many utilities traverse these trees, search them, add and delete nodes, and in general provide procedural tools with which to deal with files. The same is true of MS-DOS and Macintosh systems. The opportunity is afforded to avoid reinventing the wheel.
This really is a revolution in computing. Working with great tools will spoil you, but most of the computing world is still writing COBOL. To have to go back and forth between such environments is painful.
A good 4GL should be written in C — once. It should be written to be so general in purpose and so easy to use that its functionality can be used from then on, rather than recoded in each application. Then these good programs can be used to put together applications, not coding each entire application in C, unless there is some critical need.
As you become more familiar with their environment, you will become more able to use the power of these advanced systems. if only to shorten repetitive command sequences — another key feature of 4GLs. Every computing environment has facilities to collapse a sequence of keystrokes; these include aliasing, scripting, and macro construction.
Marketing people got wind of 4GL and turned it into a big marketing hype. Most data base management systems wrote their own procedural language like COBOL or RPG and called it a4GL. They are usually worse than COBOL, because you have to learn their new language. rather than use a classic. Few 4GL designers put as much time and energy into designing their language as was put into COBOL.
The driving force behind fourth-generation languages comes from several needs. Programming projects commonly involve man-years of work. The shortage of experienced software engineers and the need to increase productivity pushes us towards tools allowing faster development cycles. The increased use of computers by users who do not have formal computer science education requires very high-level tools that let novice programmers concentrate on algorithms rather then implementation details. As more work is done on computers, there is more demand for single-use programs to perform a specific task. The
*— PDF-Seite 17 · Buchseite 7 —*
relatively high expense of coding a software tool with a one time use encourages the use of any method available for simplifying the development process.
As third-generation languages are becoming increasingly less able to meet the diverse needs of computer users, several principles of software design are gaining great popularity. especially within the UNIX/COHERENT community:
. Data should be kept in flat ASCII files, not binary, so that we can always see what we are doing, and do not have to depend upon some special program to decode our data for us.
- Programming should be done in fourth-generation languages, except when the expected heavy use and/or resource consumption of the program justify the expense of a more efficient coding in a third generation language.
: Programs should be small and should pass data on to other programs. Software prisons, or large programs with self-contained environments, must be avoided because they require learning and they make extracting data difficult.
- We should build software and systems to meet interface standards so we can share software and stop dreaming that any individual or company can do it all from scratch.
Approaching software engineering with principles like these does have some drawbacks. The major drawback is that fourth-generation languages almost always produce slower code then third generation languages do. As computers increase in speed and power, this drawback becomes less of a consideration. As improved compiler optimization techniques spread, the difference between code produced by 3GLs and 4GLs will become smaller.
## A Paradigm
A programming paradigm is important for ensuring that a language is robust and has a consistent style to its syntax and semantics. Paradigms for fourth-generation languages must meet requirements more stringent than those for third-generation languages. To start, a fourth-generation language should provide a consistent interface to high-level facilities working with a variety of complex data types, while simultaneously providing fundamental low-level language constructs for coding any functionality missing from the predefined facilities. Too many 4GL’s are good only for projects within a narrow application area. It's difficult to allow for high-level constructs from a variety of fields without the programmer having to specify the level of detail required in a 3GL.
The paradigm we choose for fourth-generation languages is the operator/stream paradigm. In this model, data flows in unidirectional “streams” on which operators are placed. Each operator transforms the data as it passes by. The set of streams in a program form a directed graph, possibly with cycles. This paradigm concentrates on what needs to be done to the data, and deemphasizes the techniques used in the transformation.
Fourth-generation languages that attempt to use only the procedural paradigm of mainstream third-generation languages usually end up being limited to a\_ specific application domain. The procedural model doesn't describe data in an abstract enough way. Different types of operations require too much detailed code to work with. and the languages do not have the simple relation between all data and operators the way an operator/stream paradigm does.
A side benefit of using the operator/stream paradigm appears in the design of graphical programming tools. Traditional third-generation languages haven't been well adapted to a graphical programming interface. The problem stems, in part, from the difficulty of expressing the numerous possibilities in an intuitive pictorial way. With operator/stream as the basis for a language, a graphical programming aid can easily convey the process of
*— PDF-Seite 18 · Buchseite 8 —*
Introduction
placing an operator on a stream.
The operator/stream paradigm has proven effective in more domains than just language design. Some UNIX kernels make use of the paradigm to reduce the complexity of the operating-system code. Rather than having one large, complex piece of code handling all the functionality of a particular aspect of the operating system (such as a device driver), data in the kernel is run through a linked set of operators, each operator performing one small, well-defined function. This lets users modify the system by introducing new operators, without having to understand the innards of other operators on the stream.
## The Shell
The shell and the set of COHERENT utilities form a fourth-generation language based on the operator/stream paradigm. The critical feature of the shell that puts it in the class of 4GL's is the COHERENT pipe, which allows a shell to start a sequence of processes, each reading its input from its predecessor process and writing its output to a successor process. The pipe is one of the major reasons leading to the adoption of UNIX and its offspring. including COHERENT, as the standard multi-user operating system. Unfortunately. few people fully understand the philosophy behind it; most software developers are still producing large, self-contained applications using data formats incompatible with anything else.
For the shell, the COHERENT pipe provides the data streams, and the hundreds of standard COHERENT utilities provide the core set of operators. The power of this approach is tremendous. Because the data streams are flat ASCII, all the operators can read each other's data. COHERENT includes a few standard utilities that can perform most of the data formatting needed to transform one program's output to the form required by another. In addition, using stand-alone programs as operators allows easy use of custom or commercial packages of operators, such as statistics or data base packages. This modularity encourages code reuse, and the flat ASCII stream format makes it easy to get operators from a variety of sources talking to each other. Finally, because the operators can only transform the data stream running through them, side effects can’t surprise the software engineer by giving unexpected results,
The COHERENT file system also provides a hierarchal storage medium for data. Because COHERENT files are flat ASCII data files, and COHERENT deliberately attempts to make all data sources look the same, most utilities can't distinguish between data coming from a stream and data coming from a file. This gives great flexibility, allowing the shell to store the results of a pipeline into a file, and then feed that data back into a stream at some future point.
There are two frequent criticisms of fourth-generation languages. It is often noted that 4GL's tend to be suited for a particular application area, and that their low-level facilities are not up to the task of providing complex functions that don't already exist in the highlevel library. The shell escapes this problem: COHERENT utilities can be written in any language, from shell scripts to assembly language. If a tool is needed which isn't currently available, the developer is free to pick the language most suited to solving the problem, whether it’s a CASE tool or standard C. This ability to combine the shell with products of all other existing development tools results in a uniquely general 4GL.
Many also complain that fourth-generation languages sacrifice too much efficiency for the sake of short source code and high-speed development, The ability to use operators from any source is an answer to this complaint as well. It allows a shell programmer to code speed-critical routines in a language more suited to efficiency considerations. If an application requires floating-point number crunching, one codes the appropriate routines in FORTRAN and the non—time-critical sections of the code can still be done in the high-level
*— PDF-Seite 19 · Buchseite 9 —*
shell code.
With the shell, development is quite easy for even the novice programmer. The interpreted environment allows easy access to the internals of the script as it runs, as well as a fast test-change-test cycle. The flat ASCII data format and lack of operator side-effects make it easy to examine the effect different operators have on the stream of data.
## Shell Operators
The shell relies heavily on its operators. For example, it has no built-in ability to evaluate expressions; instead, it uses the test utility to to that.
The “string” data type is the only one the shell supports. The shell assumes that there are operators which will do any more advanced data type a programmer might need. Operators exist to perform numerical functions. For multi-field records. operators commonly use the space or tab character as a field separator and the newline character as a record terminator. This allows great flexibility, despite the overhead incurred of converting data into and out of ASCIl for non-string operations.
One of the greatest strengths of the shell is the ability to process an entire file with a single command. The shell does allow for defining procedures, as well as execution control constructs like if, while, and case. However, these flow-control constructs are often not needed. For example, the script presented in the following section explicitly performs no looping, because the operators implicitly loop, acting on each line of the program.
## Compatibility with MS-DOS
MS-DOS shares key underlying features with COHERENT, enough so that the operator/stream paradigm can be utilized identically in both environments. Except for minor limitations on file name syntax, the MS-DOS hierarchically structured file system appears to the user to be functionally identical to the COHERENT file system. The multitasking capabilities of COHERENT, while missing from DOS, are not essential elements of the paradigm. Although DOS shells use intermediate temporary files to implement pipes. the interface presented to users, even using command.com, can be described with the operator/stream terminology we use here. The COHERENT shell and awk are available as MS-DOS shell replacements and enhancements.
Conclusion
The shell is quite a powerful tool indeed. It is not without limitations, however. First, only a few companies are currently producing tools oriented towards use in shell scripts. /rdb remedies the shell's weakness of not being able to store complex data types, and there are many additional tools for for correcting some of the other major limitations, such as numerical computation, statistical analysis, and business graphics output. Although COHERENT has applications dedicated to mathematics and numerical analysis, most are themselves large self-contained programs. A programmer who needed matrix inversions, for example, must adapt existing tools, like System S or SAS, to work within shell scripts, or write a special purpose tool.
The shell needs improvement in the ability to connect multiple pipes together more freely. The original designers didn’t anticipate the need for more than linear pipelines. Although more complex, non-linear pipes can be created by the use of temporary files, this method is only barely adequate for constructing complex structures such as cyclic streams. Finally. more operators are needed that allow incoming data to be split between or duplicated on multiple output pipes.
*— PDF-Seite 20 · Buchseite 10 —*
The shell shares another problem with weakly typed languages: errors in the format of that data stream can lead to unexpected output. Because no method of type- or format-checking is built into the shell, the programmer must write code that avoids the problem. The interpreted environment does allow careful examination of the stream data as it passes through each operator, which reduces the difficulty of writing error free code. The shell won't lend itself to the sort of correctness proofs offered by the newer CASE tools unless a formal definition is proffered, specifying not only syntax but all the operators as well.
The operator/stream paradigm has produced a simple, powerful, general purpose tool. It allows one to prototype or generate a proof of concept in hours or days. when it might have required weeks with C. Although the shell produces slower code than a third-generation language, the increasing power of modern computers makes this a minor concern for many tasks. This framework provides an easily visualizable way of manipulating large (or small) amounts of structured data.
Although there is currently a shortage of utilities designed for general-purpose use within shell scripts, awareness of the potential of shell programming is spreading, and more packages are being written outside of the traditional monolithic program tradition. In this way, computing is coming full circle, returning to the original concepts of Von Neumann, whose computing paradigm embodies the stream of sequential memory passing by the operator of the central processing unit.
*— PDF-Seite 21 · Buchseite 11 —*
# Section 2 — Relational Data Bases
Files
The central idea of relational data bases is that all information can be put into tables and can be manipulated by a few simple operations. This is a revolutionary idea and takes some thinking to understand. It means that all of our information needs can be handled in a simple way. All information, data. knowledge. facts. or whatever you call it. can be put into tables. For example, a table named expenses might look like this:
```text
Date Amount Account Description
850125 67.00 4120 plane ticket
850126 12.00 4120 meal with client
850127 150.00 4120 hotel bill
```
At the top of the table are the column names. The dashed line makes it easier to read, and separates the header from the data rows. Each row of the table holds information about a particular expense item.
We see information in tables every day — train schedules, scientific data, phone books, restaurant menus, price lists, catalogs, math tables, conversion tables, accounting and financial reports, tax forms, and so on. We all understand tables: we know how to fill them in and how to look up information in them. Tables and our operations on tables are independent of the information they contain. The purpose of this book is to help you to think about your information problems in terms of tables and operations on tables.
In accounting, information is collected in journals, then manipulated to create financial statements that you can review to see the state of the business. Scientists have instruments in their labs that collect data and store it in their computers. Statistical programs compress masses of data into simple tables and graphs for the scientist to look at to see responses of systems to various inputs and to discover causal relationships. Employee information is stored in tables and can be extracted to print pay checks, make phone books, and so on.
When we take these abstract ideas to the COHERENT system, we find a friendly environment for storing tables and manipulating them. Computers store tables in files that live on hard disks. They have names by which they can be called up. Tables can be created with a text editor, with COHERENT commands, from other tables, or imported from other COHERENT data base systems, or even foreign systems. Once tables are implemented as ordinary COHERENT files, there is available a plethora of COHERENT utilities for maintaining security, data integrity. and ancillary information about tables.
There are only three rules for creating a table in the COHERENT and /rdb environment:
- A tab is inserted between each column.
- On the first line of the table, each column is given a name.
*— PDF-Seite 22 · Buchseite 12 —*
- The second line of the table has lines of dashes for each column, showing the width of the column.
This is much easier for the user than systems that require the overhead of setting up schema and special files. Once tables are created, they can be manipulated by COHERENT and /rdb. Using the ve forms editor to initially create tables and enter data from your terminal avoids potential problems caused by (among other things) the wrong number of tabs.
Columns
Rows
When we try to look up information in a table, we usually find that there is a lot more information there than we want. We have to find the single fact we want from all the rest. Often. there are more columns than we need. Therefore, we want to reduce the table to only those columns we need. When we look at a table with our eyes, we try to ignore the extra columns. Or we use our fingers to scan down the column we want.
When using the computer we have a command called column, which is a program that inputs one table and outputs another table that has only the columns you specify. For example consider our expenses table. One can project some of the columns of a table by typing this simple command, which says to project columns Amount and Description from the input expenses table:
```text
column Amount
This produces:
Amount Description
```
```text
67.00 plane ticket
12.00 meal with client
150.00 hotel bill
```
Note that now we have a new, smaller table with only the two columns we want to see. For another example, you might project just the names and phone numbers from the employee table to make a phone book. In other words, the company phone book is a projection of the name and phone columns of the employee table.
The most common operation is to search the table for a specific piece of information. We want to know when the next plane leaves, the price of the scallops on the menu, the degrees Centigrade for 72° Fahrenheit, the ball player with the highest batting average, the grade for a class on a report card, the amount spent on phone calls by the company last year, and so on. Each search requires that we select just one, or a few, rows from a table.
On the computer, you can select only the rows desired with the row command. Here we select all rows in the expenses table in which Amount is greater than 50:
```text
row ‘Amount > 50’ < expenses
```
This produces:
*— PDF-Seite 23 · Buchseite 13 —*
```text
Date Amount Account Description
850125 67.00 4120 plane ticket
850127 150.00 4120 hotel bill
```
With one simple operation you can select information from any table containing any data.
## Columns and Rows
Often you want to find one or a few rows and see only a few columns. On COHERENT you can put these two commands together. The COHERENT pipe symbol ‘|’ means to take the table that is output from the column command on the left and input it into the row command on the right:
column Amount Description \< expenses | row ‘Amount \> 50’
```text
This produces:
Amount Description
```
```text
67.00 plane ticket
150.00 hotel bill
```
Since the output of one program can be piped into the input of another, you can create report programs with one or a few lines of commands and pipes. For example, you can project some columns of a table with the column command, pipe the output to a row program which will select certain rows, pipe that output to a sorttable program which sorts it, then on to a jointable to pick up other columns from another table. All of this can be done by typing one line on your terminal. Or this line can be typed into a shell program file with a text editor, and given a name, like weeklyreport. Then, by simply typing weeklyreport, the report can be produced when you wish. Several reports can be invoked by a higher level shell script. This is called shell programming.
These reports, and other programs, can be placed in a menu and selected with a few keystrokes, or if you have a terminal with a mouse, by pointing and clicking. Therefore, you can automate whole operations in hours and days, rather than the months and years that it takes on other systems.
## Shell Programming and Flat ASCII Files
The key to this approach is shell programming and flat ASCII files. Flat means there is no structure to them. COHERENT thinks of them as a stream of characters. ASCII is a standard code for converting characters to numbers for storage in the computer. The files have variable length records and fields. This is a break from the IBM tradition of structured binary files with fixed length records and fields. Breaking with this old tradition is an essential part of the COHERENT revolution.
This does not mean that /rdb cannot manipulate binary data. We will discuss manipulating arbitrary binary objects later.
*— PDF-Seite 24 · Buchseite 14 —*
Lists
In addition to the table format shown previously, /rdb also has a list format for data that is hard to fit into a table, such as mailing lists. For example:
Number 1
Name Rambo
```text
Company One Man Army
Street 123 Mac Attack
City Anywhere
```
State Thirdworld
ZIP 30000
Phone (111) 222-3333
```text
Number 2
Name Chuck
Company eee
```
Note that the list format begins with a blank line, unlike the table format, and that a single tab separates the field name from the data for each field. You can use the COHERENT vi text editor or /rdb's ve form editor to initially create tables, and to enter and edit data ina table. You can convert from table to list and from list to table format easily with the tabletolist and listtotable commands.
Review
A relational data base is a collection of relations or tables that may be related on one or more common columns. Relational data bases implemented like this are easily transportable from one environment to another.
Relational data bases have a solid mathematical base in relational set theory, relational algebra, and relational calculus. There are theorems in this relational math that prove that any data put into a relational data base can be extracted. The mathematical base also assures that manipulations performed will have correct results, just as arithmetic assures us that the math functions we perform on the computer have correct results.
## Normal Relations
An /rdb relation, or table, is an ordinary ASCII file. An /rdb table has rows, or records, separated by newlines. It has fields, or columns, separated by a tab character. Every row must have the same number of columns. This is first-degree normalization.
The first row of a table contains the names of the columns; the second row contains columns of dashes. Any kind of information can be represented in such a table: numbers, words, file names, etc: /rdb commands and relational set theory doesn’t care about the content of the table — just as long as these rules are followed for the form of tables. Another important rule to remember when designing a data base is:
If many columns are used in a single row to describe the same type of information, it's time to make a new table.
For example, consider a table of family members:
*— PDF-Seite 25 · Buchseite 15 —*
```text
id mom dad kidl kid2
a: mary jack billy bobby
2 nancy joe terry susie
3 sally john adam
```
In this example there are two kid columns in each row. The right way to express this relationship is with two tables: one for parents and one for kids. They are related or linked by a common column, id.
```text
id mom dad
1 mary jack
2 nancy joe
3 sally john
```
```text
id kid
1 billy
1 bobby
2 terry
2 susie
3 adam
```
## How Is Information Accessed?
Tables are accessed through /rdb and shell commands issued at the COHERENT prompt or from within shell or C programs. Here is a list of some common /rdb commands which are used or mentioned in these examples.
Selected /rdb Commands
```text
[TED COMMANA......00escerrevserseorereres
```
```text
column, project.
row, select
```
mean......
```text
jointable
```
```text
sorttable
```
```text
compute Do calculations on columns
subtotal... Subtotal selected columns
total. Total selected columns
```
```text
Change the name of a column
Make a table line up properly
..Remove the first two header rows
. Report writer
```
..Mi-like table editor
/rdb commands are programs that read tables from the standard input and write tables to the standard output. Suppose there's a table that looks like this:
*— PDF-Seite 26 · Buchseite 16 —*
```text
Item Amount Cost Value Description
1 3 50 150 rubber gloves
2 100 5 500 test tubes
3 5 80 400 clamps
4 23 19 437 plates
5 99 24 2376 cleaning cloth
6 89 147 13083 bunsen burners
v 5 175 875 scales
Then a sample query might be:
column Item Cost Amount < inventory
This produces:
Item Cost Amount
1 50 3
2 } 100
3 80 5
4 19 23
5 24 99
6 147 89
7 175 5
```
This is read aloud as: “Select the Item, Cost, and Amount columns from the inventory table.” It's important to voice queries because people often type stuff in that they would never say out loud.
```text
The query:
row ‘Cost > 50’ < inventory
```
This produces:
Item Amount Cost
Value Description
```text
3 5 80 500 clamps
6 89 147 16353.8 bunsen burners
% 5 175 1093.75 scales
```
This reads, “Select rows where the Cost column ts greater than 50 from the inventory table." To put commands together:
column Item Cost Value \< inventory | row ‘Cost \> 50’
This produces:
```text
Item Cost Value
3 80 400
6 147 13083
7 175 875
```
This is pronounced, “Select the Item, Cost and Value columns from the inventory file and
*— PDF-Seite 27 · Buchseite 17 —*
select those rows where Cost is greater than 50.” Inside the apostrophes the \< and \> symbols are pronounced less than and greater than respectively, whereas outside apostrophes they are pronounced from and to. The pipe symbol \*|" is pronounced and.
To take the mean of the result while listing each line:
```text
column Item Cost Value < inventory | row ‘Cost > 50’ | mean -1l Value
This produces:
Item Cost Value
```
```text
3 80 400
6 147 13083
7 175 875
```
4786
## Creating Tables and Entering Data
There are many different ways to create tables; editors, programs, shell commands such as sed or awk, etc. Most often, however, when /rdb tables are entered from scratch, ve, the /rdb table editor is used. ve allows the creation of tables quickly and in a familiar and easy way. It's a lot like vi. The first step in the creation of a table with ve is to create a screen definition file with any editor. This can be accomplished with any editor. Here is a ‘screen’ file for the states file:
```text
The States File
st < st >
state < state >
```
ve uses this screen file to create the table. The rules for screen files are simple:
1. Column names go inside the angle brackets.
2. Anything outside of angle brackets is just text that appears on the screen.
The space between angle brackets is the viewable window over the field, and isn't a restriction on how wide the field can really be. After creating a screen file like this:
```text
ve states
```
and the states file will be created. Let's say ve has been used to add new records to our states table so that it looks like this:
```text
st state
```
```text
cA California
NV Nevada
```
## NY New York
A mailing list can be created the same way, by making a ‘screen’ file and then using ve to add a few rows:
*— PDF-Seite 28 · Buchseite 18 —*
Yet Another Mailing List
```text
Name
```
```text
Street
```
```text
City
```
```text
State
```
The command justify adjusts the mailing list, to make it appear neater. For example, the command
```text
justify < mlist
```
produces:
```text
name address city st
```
```text
Evan Main St. Santa Cruz CA
Rod Broadway Ithaca NY
```
The next command
```text
column st name < mlist |
sorttable |
jointable - states
```
reads, “Select the st and name columns from mlist and join it with the states table.” It produces the following:
```text
st name state
CA Evan California
NY Rod New York
```
The sorttable command was silent. But it has to be there. Both files to be joined must be sorted. The states file is already sorted. The dash in the jointable command means use the standard input. just like the COHERENT join command.
Reports
For numeric information, /rdb's standard table output adjusted with a justify or trim command is often sufficient, especially when combined with tabletotbl and the UNIX tbl and the COHERENT nroff/troff formatters. In addition to these methods, /rdb has a report command that uses a prototype report form and has built-in command processing capabilities.
Let's look at a sample report form. It’s like the screen file for ve: text is outside brackets. and column names are inside brackets. Other commands can also go inside the brackets. Here's a report form for the mlist file:
*— PDF-Seite 29 · Buchseite 19 —*
```text
< city >,
Dear < name >,
This is a computer chain letter.
I am also sending it to:
```
```text
"’ | justify !>
Bye, I>.
```
Thus, the command
```text
row ‘name ~ /Evan/' < mlist | report mlist.form
produces the following output:
```
```text
Evan
Main St.
Santa Cruz, CA
```
```text
09/03/89
Dear Evan:
This is a computer chain letter.
I am also sending it to:
```
```text
name city
```
```text
Rod Ithaca
Bye, Evan.
```
Arbitrary text goes outside the angle brackets; column names go inside angle brackets, and any arbitrary command or shell program or shell command(s) can go between exclamation marks within angle brackets, and you can still specify columns from the current record therein. You can even have reports within reports.
## The Big Text Field Problem
The “bug report,” “long text column,” and “every word indexed” problems are all facets of the same situation. Let's say a file has some relatively short columns, and one or more long text columns on which you'd like to use vi.
Take the case of a bug report data base with associated arbitrarily long narrative descriptions: a solution is to keep the descriptions in a sub-directory called, for example, bugreports, one file per record, with the file name being bugreports/recid where recid is the record identifier from the current record. Then, a control key is mapped in the .vere file (analogous to the vi's .exrc file) to the command vi bugreports/\. This grabs an identifying column from the record, constructs the name of the associated file(s), and pops the user into vi on the named file(s). This is quite flexible even if there is more than one file associated with each record, switching between ve files with a keystroke, thus effecting multiple screens: map a control-key to write the record and switch the files, and another to switch back.
*— PDF-Seite 30 · Buchseite 20 —*
A simple report makes a two column table with record id and word for each word in each narrative, allowing for queries like Give me all the bugs mentioning word ‘xyzzy’:
```text
#1/bin/sh
```
```text
(echo “word id"
echo “---- --"
for i in [0-9]*
```
```text
do
```
```text
word < $i | awk ‘{print $1,"'$i'"}’
done) |
sorttable -u
```
Now records having a particular word can be found easily. If speed is a consideration, build an(other) inverted index on the word/id concordance list just created:
```text
ed bugreports
```
```text
wordy > bugwords
```
```text
index -mi -x bugwords word
```
```text
echo xyzzy | search -mi -x bugwords word
```
This produces a list of record ID numbers on the standard output. Once you have the record ID numbers, one more search is necessary to find the original record in the bugs table. Of course, with the record ID numbers, no search is necessary to find the narrative, because the file name ts the record id.
## Non-Text Data Structures
Suppose a field is a picture, or a sound, or some other non-textual object. The /rdb approach is to identify an object resource, with text, within a field in a table, describing the type and location of the object. Fields from the current record can be referenced in the -vere file by the same \ specification used in the report program and customized ve screen files.
## Large Tables
Large tables are often as easily handled as small tables. When working with very large tables some form of indexing is desirable: hash, inverted sequential secondary, binary (sorted relations), or some form of tree (linked list).
The shell approach is to use the COHERENT directory structure as the first (few) levels of tree index. One financial application using /rdb involves the 80-megabyte file of time series from the International Monetary Fund. As distributed, it takes several large machine CPU minutes to peruse this big file and extract a single time series. The file was divided into a directory for each country and within each country directory. a file for each time series, with the file name being the time series code as given by the IMF. Each of those time series files is a /rdb file, with columns YR ANN Q1 Q2 Q3 Q4 and so forth. A separate “description” file in each country directory has a line for each file in the directory. giving CODE DESCRIPTION UNITS.
Thus, the time to retrieve any time series (if the country and time series code are known) is independent of the size of the data base. Queries like “which countries have this time series in common?” are answered with the Ils command. More than one level of index can of course be implemented just by adding directory hierarchies.
*— PDF-Seite 31 · Buchseite 21 —*
COHERENT has many commands to traverse directory trees, and to add, delete, and otherwise manipulate nodes. With this approach, nodes are tables, and the plethora of COHERENT directory and file handling commands are all relational data base manipulation commands.
Architectural Performance Enhancements
SQL
Learning to use the COHERENT utilities has a much greater value than learning yet another special programming language. Once a small critical mass of COHERENT familiarity is achieved, application development becomes little more than writing simple yet powerful scripts to perform tasks which used to be laboriously performed by hand, or just not done at all.
All these techniques comprise a marriage of the facilities that come with the COHERENT system itself, and relational capabilities provided by /rdb.
This attitude of not reinventing the wheel is the basis of the shell and /rdb approach. All COHERENT knowledge is knowledge about data bases, and experiences with data bases teach more about COHERENT. That's why the combination of the /rdb extensions to COHERENT and the shell command language is a 4GL most appropriate to the COHERENT environment.
SQL is another language for querying a data base. It's used as the foundation for many contemporary 4GLs. It does not use the stream/operator paradigm, but “nests” queries to pass data from one operator to another. When SQL was developed, COHERENT had not yet been invented, so an entire environment had to be developed to express queries. SQL is another system to learn, with little use outside of itself. and typically no relation to the operating environment surrounding it.
SQL does not specify any particular file format. Although there is an ANSI standard SQL for expressing queries, implementors are free to store data however they want. In a way. this is a contradiction, because getting away from these walls that stand between data is very important, and was the principal reason that the concept of a data base came about. The idea goes under the name of integrated and modeless software, and most recently, interoperability.
There are reasons why SQL-based systems are popular, even desirable. SQL-based systems are widely available and there is a large body of expertise also readily available. Many U.S.- government agencies require access to corporate data bases via SQL, especially in the defense industry. SQL is valuable in non-COHERENT environments. Partly because SQL is difficult for novices to understand and use, SQL providers typically field a large, helpful support organization. Of course, this drives the price up. and doesn’t adequately address the needs that prompted the development of these tools in the first place: making nonexperts proficient and productive in the construction of basic data base applications.
```text
SQL queries can be converted to shell scripts:
SQL COHERENT and /rdb
```
```text
select coll col2 from filename......column coll col2 < filename
where column - expression ...... row ‘column == expression’
```
```text
compute column = expression .compute ‘column = expression’
group by.. subtotal
having...... .row
```
```text
order by column +.sorttable column
```
*— PDF-Seite 32 · Buchseite 22 —*
+ unig
```text
wwe =1
```
```text
outer join.. jointable -al
update...... delete, replace
HESUING csccsscesscceses pipes
```
## Fifth-Generation Systems
There is a distinction to be made between fourth-generation languages and CASE tools. The programmer of a fourth-generation system must still specify the fundamental algorithms for completing a task, perhaps at a higher level of abstraction, especially of data types. CASE tools, on the other hand, require only a specification of the task, and generate not only the code, but also the algorithm. CASE tools tend to be of very limited domain. An example would be a screen layout tool. The developer draws the positions of the windows wanted. and the tool generates the code to create the windows, manage the text and graphics inside them, and deal with icons and menus.
Some graphical CASE tools are examples of what we might call 5GLs. Using a graphical user interface, these tools allow applications to be built by example. Some force the user to specify actions algorithmically, and some do not. There's even less agreement about what constitutes a 5GL than there is about 4GLs.
The operator/stream paradigm has produced a simple, powerful, general purpose tool. It allows one to prototype or generate a proof of concept in hours or days, when it might have required weeks with C. Although the shell produces slower code than a third-generation language. the increasing power of modern computers makes this a minor concern for many tasks. This framework provides an easily visualizable way of manipulating large (or small) amounts of structured data.
Although there is currently a shortage of utilities designed for general purpose use within shell scripts, awareness of the potential of shell programming is spreading, and more packages are being written outside of the traditional monolithic program tradition. In this way, computing is coming full circle, returning to the original concepts of Von Neumann. whose computing paradigm embodies the stream of sequential memory passing by the operator of the central processing unit.
References
Kernighan B., Pike R.: The UNIX Programming Environment, Englewood Cliffs, NJ: Prentice Hall, 1985.
Kochan S., Wood P.: UNIX Shell Programming. Hayden Book Company, 1985.
Prata S.; Advanced UNIX — A Programmers Guide. Indianapolis: Howard W. Sams and Co., Inc., 1985.
A. Winston: "4GL Faceoff: A look at Fourth-Generation Languages," UNIX/World, July 1986, pp. 34-41.
Misra S., Jalics P.: “Third-Generation versus Fourth-Generation Software Development.” IEEE Software, July 1988, pp. 8-14.
Manis R., Schaffer E., Jorgensen R.: UNIX Relational Database Management. Englewood Cliffs, NJ: Prentice Hall, 1988.
Verner J., Tate G.: “Estimating Size and Effort in Fourth-Generation Development,” IEEE Software, July 1988, pp 15-22.
*— PDF-Seite 33 · Buchseite 23 —*
Matos V., Jalics P.: “An Experimental Analysis Of The Performance Of Fourth Generation Tools On PCs," Communications of the ACM, November 1989, pp. 1340-1351.
Manis R., Meyer M.: UNIX Shell Programming. Indianapolis: Howard W. Sams Inc.. 1987.
*— PDF-Seite 34 · Buchseite 24 —*
*— PDF-Seite 35 · Buchseite 25 —*
# Section 3 — Commands, I/O, Pipes
/rdb commands are programs that read tables from the standard input and write tables to the standard output. Once data are entered into tables, they are accessed through /rdb and shell commands issued at the COHERENT prompt or from within shell or C programs. This is an easy way to ask questions of, or query, the data base. Here is a list of some common /rdb commands which are used or mentioned in the following example queries:
```text
/rdb command Description
```
column, project... . Select only certain columns
```text
row, select Select only certain rows
mean...... Compute the mean of selected columns
jointable . Join two tables
sorttable . Sort a table
compute Do calculations on columns
subtotal Subtotal selected columns
total. .. Total selected columns
rename ..Change the name of a column
justify. Make a table line up properly
headoff Remove the first two header rows
report . Report writer
Suppose there's a table that looks like this:
Item Amount Cost Value Description
```
1 3 50 150 rubber gloves
2 100 5 500 test tubes
3 5 80 400 clamps
4 23 19 437 plates
5 99 24 2376 cleaning cloth
6 89 147 13083 bunsen burners
7 5 175 875 scales
Then a sample query might be: 6
```text
column Item Cost Amount < inventory
```
Which produces:
*— PDF-Seite 36 · Buchseite 26 —*
```text
Item Cost Amount
1 50 3
2 5 100
3 80 5
4 i9 23
5 24 99
6 147 89
y | 175 5
```
```text
This is read aloud as: “Select the Item, Cost, and Amount columns from the inventory
table."
```
```text
In another example, the command
row ‘Cost > 50’ < inventory
```
This is, ‘Select rows where the Cost column Is greater than 50 from the inventory table.” This yields:
```text
Item Amount Cost Value Description
3 5 80 400 clamps
6 89 147 13083 bunsen burners
a 5 175 875 scales
```
```text
The next example puts the commands together:
column Item Cost Value < inventory | row ‘Cost > 50’
```
This is pronounced, “Select the Item, Cost and Value columns from the inventory file and select those rows where Cost is greater than 50." This yields:
```text
Item Cost Amount
3 80 5
6 147 89
7 175 5
```
Between the apostrophes, the \< and \> symbols are pronounced “less than” and “greater than” respectively, whereas outside apostrophes they are pronounced “from” and “to”. The pipe symbol ‘| ‘symbol is pronounced “and”.
To take the mean of the result while listing each line, do the following:
```text
column Item Cost Value < inventory | row ‘Cost > 50’ | mean -1l Value
This yields:
Item Cost Amount
3 80 5
6 147 89
7 175 5
4786
```
*— PDF-Seite 37 · Buchseite 27 —*
You can use the name select instead of row. The Korn shell has a select command, and /rdb uses row as a synonym for select. We give the same program two names by using the COHERENT link command In.
```text
compute: Compute a New Result
```
The command compute lets you calculate one column as a function of other columns, or constants. For example, you could calculate the Value column in your inventory table as Onhand times Cost with this command:
compute ‘Value = Onhand \* Cost’ \< inventory
This yields
```text
Item Onhand Cost Value Description
1 3 5 15 rubber gloves
2 100 1 100 test tubes
3 5 8 40 clamps
4 23 2 46 plates
5 99 3 297 cleaning cloth
6 89 18 1602 bunsen burners
7 5 175 875 scales
```
For a fancier example, add $5 to the Cost of item 4 only, and recompute the Value column:
```text
compute ‘if (Item == 4) \
Cost += 5; Value = Onhand * Cost’ < inventory
```
This yields:
```text
Item Onhand Cost Value Description
1 3 5 15 rubber gloves
2 100 1 100 test tubes
3 5 8 40 clamps
4 23 7 161 plates
5 99 F 297 cleaning cloth
6 89 18 1602 bunsen burners
7 5 175 875 scales
```
Note that the Cost of item 4 is now 7 (2+5). You can also write commands down the page. From the line on which you open the apostrophe until you enter the closing apostrophe, the shell will keep reading lines. You can do lots of powerful calculations with compute. See the /rdb manual pages for compute, and read the awk tutorial in your COHERENT documentation.
```text
justify: Align Columns
```
Often when you type in a table, or for other reasons, the columns containing numbers might be left justified. For example:
*— PDF-Seite 38 · Buchseite 28 —*
Item Onhand Cost Value Description
```text
1 3 5 15 rubber gloves
2 100 1 100 test tubes
```
3 5 8 40 clamps
4 23 ng 161 plates
```text
5 99 3 297 cleaning cloth
6 89 18 1602 bunsen burners
7 5 175 875 scales
```
In this inventory table, you may not like looking at number columns left justified. It is not the way we usually see numbers in tables. But it is an easy way to enter data into a table with a text editor because we do not have to space over to line up our numbers. To make our table a lot prettier, the justify command is available. It right-justifies numbers and leftjustifies strings. It also blank fills the character columns, so that they can be placed in any order and the columns to their right will still line up.
For example, it might be easier to enter the inventory table as shown previously. Then the justify command can be used to right justify the numerical columns:
```text
justify Onhand Value Cost < inventory
```
This yields:
Item Onhand Cost Value Description
```text
i! 3 5 15 rubber gloves
2 100 ay 100 test tubes
```
3 5 8 40 clamps
4 23 7 161 plates
```text
5 99 3 297 cleaning cloth
6 89 18 1602 bunsen burners
if 5 175 875 scales
```
Only the columns selected were justified, including their column headings. Item was not selected and was not justified. Now if we project the columns in inventory in a different order, the columns will line up correctly:
column Description Item Onhand Cost Value \< inventory
which yields:
```text
Description Item Onhand Cost Value
rubber gloves 1 3 5 15
test tubes 2 100 1 100
clamps 3 5 8 40
plates 4 23 2 Si
cleaning cloth 5 99 3 297
bunsen burners 6 89 18 1602
scales 7 5 175 875
```
*— PDF-Seite 39 · Buchseite 29 —*
```text
total: Compute Arithmetic Totals
```
To total columns of a table simply type:
```text
total < inventory
```
```text
This yields:
Item Onhand Cost Value Description
28 324 212 2980
```
Note that we have totaled the Item. Onhand, and Cost columns. Summing these columns does not make much sense, but total, in this automatic or default mode, operates on all numeric columns. Naming specific columns will result in your getting only those columns totaled. Only numeric columns can be totaled.
The -1 option lets you see the whole table. (The 1 in -lis the letter “el”, not the number one.) For example, the command
```text
total -l Value < inventory
```
yields:
Item Onhand Cost Value Description
```text
1 3 5 15 rubber gloves
2 100 1 100 test tubes
```
3 5 8 40 clamps
4 23 2 51 plates
```text
s 99 3 297 cleaning cloth
6 89 18 1602 bunsen burners
7 5 175 875 scales
```
```text
subtotal: Compute a Subtotal
```
To subtotal, enter the break column first, followed by the columns to be subtotaled. The break column is the column watched by the program. If, on a new row, the value in the break column is the same as the previous value in that break column, the values in the other columns are added. But if the value in the break column changes (breaks), then subtotal draws a line and prints the subtotals of the other columns. As long as the value in the break column remains the same row after row, the values in the selected columns are accumulated. When the break column's value changes, the subtotal is printed and a new subtotal is started.
For example. we might have the following ledger table:
*— PDF-Seite 40 · Buchseite 30 —*
```text
Account Date Debit Credit
101 820102 25000
101 820103 5000
101 820104 15000
130 820104 30000
150.1 820103 10000
211.61 820104 15000
211.1 820102 25000
211.1 820103 5000
```
In this example. Account is the break column and Debit and Credit are to be summed. (This is done to foot the ledger at the end of an accounting period.)
subtotal -1 Account Debit Credit \< ledger
This yields:
```text
Account Date Debit Credit
101.0 820102 25000
```
```text
101.0 820103 5000
101.0 820104 15000
101.0 25000 20000
130.0 820104 30000
```
```text
130.0 30000 0
150.1 820103 10000
```
```text
150.1 10000 0
211.1 820104 15000
211.1 820102 25000
211.1 820103 5000
211.1 ° 45000
```
Columns Debit and Credit are named on the command line, so only they are totaled, and not column Date, which would be pointless to total. Note that the value in the break column is carried down to identify the subtotal. The Account values are not subtotaled. That would also be meaningless.
The -1 tells subtotal to output the whole table. not just the subtotals. Without the -l, we would get only the subtotals. For example.
```text
subtotal Account Debit Credit < ledger
```
yields:
*— PDF-Seite 41 · Buchseite 31 —*
```text
Account Date Debit Credit
101.0 25000 20000
130.0 30000 0
150.1 10000 °
211.1 0 45000
```
## Quoting Commands
Note that the apostrophe (') goes before and after the conditional expression in the row command. This protects the expression from the COHERENT shell. The shell is the program within the COHERENT system that reads the commands you type and executes them. Without the apostrophe, the shell would see the left arrow (\<) and think we were inputting a table named 10. The apostrophe is also needed to put the whole expression together as one argument for the row command. If you need to quote something within the expression, use quotation marks ("). For example, if you had a column name with special characters (including spaces) in it, you must put it in quotation marks. For example:
row ‘'"Net Pay" == "Gross-Pay"’ \< payroll
A column name consists of upper- and lower-case letters, numbers, and the underscore character ‘\_'. Therefore, if you put special characters and spaces in column names, you will have to keep putting the quotation marks around them every time you refer to them. (This is true of C language versions of column and row. It is safest to stick with one-word column names).
Note that we use a double equals ‘==" instead of just one ‘=. This comes from the C language and the awk program, that the row and compute commands use. The rule is to use the ‘=’ to mean, “Assign the value on the right of the equal sign, to the variable on the left." Use the '==" to mean logically equal, as we used it in the row command. Another way to remember this, is that you usually use the logical equal ‘==" in row commands, and the assignment equal ‘=" in compute commands. In advanced usage, you will find that you need both in row and compute for very powerful commands.
Pipes
Pipes \*|' are a COHERENT shell mechanism that sends the output of one program to the input of another program. This allows you to perform a series of operations on a table. You now can begin to see the real power of this system. In a single line we can produce a report. If you wished to select only rows where Value was greater than 100, but wanted to see only the Description and Value columns sorted in alphabetical order, you could pipe the row command's output into the column command, which would be piped into the sorttable command like this:
```text
row ‘Value > 100’
*— PDF-Seite 42 · Buchseite 32 —*
```text
Description Value
bunsen burners 1602
cleaning cloth 297
scales 875
```
The pipe symbol |" means that the output from the program to the left becomes the input to the program on the right, or below. As with quotes, the shell will keep accepting lines ending with pipes. Therefore, you can write long pipe programs down the page. which is easier to read and debug. The sorttable program, without any columns named, defaults to sorting on the first and subsequent columns.
Warning: Never use the same file as input and output in one command or pipe. If you want to save the output that normally comes to your terminal screen in a file, use \> tmp. The tmp file name is a common name for a file that has only temporary use. It should always be ok to remove it later. For example:
```text
sorttable < inventory > tmp
```
```text
You can then move tmp to inventory:
my tmp inventory
```
```text
Now your inventory table is sorted. If you type:
sorttable < inventory > inventory
```
your inventory table will be zeroed out (have zero characters or lines in it). The reason is that the COHERENT shell, in opening the inventory file for output. zeros the file's size. Then, when the sorttable program (or any COHERENT program) reads it in, it gets EOF on the first read. It closes the file, empty! You'll get the same disastrous effect even if you pipe the output through several programs and then try to write it into the original input file. Do not do it! Also, get in the habit of looking at your tmp file before moving it onto your original good data. You may have made an error and be moving or copying bad data onto good. Finally, be careful not to type
```text
> file
when you mean:
< file
The first wipes out the file, rather than reading it.
```
## Syntax: How To Enter Commands Correctly
In the manual, you will see a synopsis of each command and its syntax. Syntax is the rules for forming a correct command. Semantics is what the resulting command will do. Computer programmers are familiar with this way of expressing the syntax rules. If you are not, read this chapter. We will start with simple syntax and go to complex. The simplest syntax is a command with no options:
```text
commands
```
You just type commands and you get all of the commands’ descriptions and their syntax rules. Most commands require an input table. For example:
```text
column < table
```
*— PDF-Seite 43 · Buchseite 33 —*
Substitute the name of your table for the table in the syntax rule. But you type the column \< exactly as specified. If you have a table named inventory, you would type:
```text
column < inventory
```
Many commands allow you to input tableorlist. This means they can handle both table and list formatted files:
```text
column < tableorlist
```
Options are placed in brackets ‘{ ]' because you do not have to type them unless you want them. For example:
```text
justify [ column ... ] < table
```
The brackets here mean that you can optionally name columns to be justified. The ellipsis ‘.... means that you can have many column names. But since there are brackets around the column ..., you can also leave them out. In which case, all the columns would be justified. Note that there are no brackets around the \< table. This part is not optional. You must have it to tell the COHERENT shell which file to open for input.
You should know that whenever you see \< table you can also use a pipe to input a table into the command:
```text
cat table | justify
This has the same effect as:
justify < table
```
If you see a vertical bar ‘|" within brackets, it means or, not a pipe. Other commands give lists of options in brackets. For example:
jointable [ -a[n] -n - ] [ -j[{n] column ] tablel [ table2 ]
This means that each option may or may not be selected. Note that there are brackets within brackets. This means that if you chose the -a, for example, you have the further option of adding a number n to specify which table number. The brackets around the - jcolumn mean that the two strings go together, as well as being optional. The column should be replaced by the name of one of the columns in one of the tables. Finally, the second table is in brackets, meaning it is optional. But the manual page goes on to explain that if it is not there. and the - option is not chosen, then the jointable command will get its second table from the standard in.
The most complex syntax is for compute. It can only be hinted at with the rule: compute ‘column = expression’ \< table
expression can be quite complex. You must look at the manual pages for compute and awk to get an idea of all of the things you can do.
## COHERENT Shell Scripts
You can also put commands (including pipes) into a file and execute the file by simply typing its name. These new commands are called views in the data-base literature because they give you a particular view of your data. Use a text editor to type the commands into a file, just as you would at the screen. Use a name for the file that you will remember and that reminds you of what you are trying to do with the series of commands, like weeklyreport. After leaving the text editor, type:
*— PDF-Seite 44 · Buchseite 34 —*
```text
chmod 755 weeklyreport
or
chmod atw weeklyreport
```
This COHERENT command makes the file executable. chmod means change mode. Whenever you want the series of commands that make up weeklyreport, just type:
```text
weeklyreport
```
You can also use this new program in other COHERENT shell script files. If you want the new program to be available to others, put it in /usr/local/bin, or some other bin that is in the path of your users.
Suppose that at the end of each day, after making changes and updates to your inventory file, you wanted to fix up the file. If you wanted to recompute the Value column, right justify the number columns and left justify (blank fill the character columns); you could pipe together compute and justify. But since you will need to perform these functions often, you could create a program. The commands to fix up a table could be saved in a file with an easy-to-remember name. For example, the fix command could look like this:
```text
# fix is a little routine to compute
# and right justify the number columns
```
```text
compute ‘Value = Onhand * Cost’ < inventory | justify
Remember to type:
```
```text
chmod 755 fix
or
```
```text
chmod at+w fix
to make it executable. If you don't, you'll see
```
## Permission denied
when you type the name of the file. (You may also see this when you type the chmod command if you don't have the right permissions.) To run fix just type its name:
```text
fix
This yields:
Item Onhand Cost Value Description
1 3 5 15 rubber gloves
2 100 i 100 test tubes
3 5 8 40 clamps
4 23 2 46 plates
5 99 3 297 cleaning cloth
6 89 18 1602 bunsen burners
Ef 5 175 875 scales
```
You can see how easy it is to write programs in the COHERENT environment. This is called shell programming. /rdb is an extension to the COHERENT system that adds data-base commands to the COHERENT commands.
*— PDF-Seite 45 · Buchseite 35 —*
COHERENT is good at this kind of levels of power. With most systems, you are limited to the functions the developers programmed into the system. With COHERENT and /rdb, you are limited only by your own imagination.
There are other useful COHERENT commands. pr will set up your output with head lines, and it will break on, and number, pages. nroff and troff can format your text and data for attractive printouts.
There are many different ways to initially create tables: editors, programs, shell commands such as sed or awk, etc. When /rdb tables are entered from scratch, ve, the /rdb table editor, is often used. ve allows the creation of tables quickly and in a familiar and easy way. It's a lot like vi. The first step in the creation of a table with ve is to create a screen definition file with any editor. Here is a screen file for the states file:
```text
The States File
st < st >
state < state >
```
ve uses this screen file to create the table. The rules for screen files are simple:
1. Column names go inside the angle brackets.
2. Anything outside of angle brackets is just text that appears on the screen.
The space between angle brackets is the viewable window over the field, and isn't a restriction on how wide the field can really be. After creating a screen file like this:
```text
ve states
```
and the states file will be created. Let's say ve has been used to add new records to our states table so that it looks like this:
```text
st state
```
```text
CA California
NV Nevada
```
## NY New York
A mailing list can be created the same way, by making a ‘screen’ file and then using ve to add a few rows:
Yet Another Mailing List
```text
Name
Street
city
State
```
This yields:
```text
name address city st
Joe Main St. Santa Cruz CA
Bob Broadway Ithaca NY
```
To “Select the st and name columns from mlist and join it with the states table."" When we run the command
*— PDF-Seite 46 · Buchseite 36 —*
```text
column st name < mlist |
```
```text
sorttable |
jointable - states
it yields:
st name state
CA Joe California
NY Bob New York
```
The sorttable command was silent. But it has to be there. Both files to be joined must be sorted. The states file is already sorted. The dash in the jointable command means use the standard input, just like the COHERENT join command.
## Report Writing
As with querying, report writing is also very easy. In fact. any query can be printed as a report by directing its output to your printer. Likewise, any report can be a query by directing it to your terminal (which is usually the default anyway).
For numeric information, /rdb's standard table output adjusted with a justify or trim command is often sufficient, especially when combined with tabletotbl and the COHERENT nroff/troff formatters. In addition to these methods, /rdb has a report command that uses a prototype report form and has built-in command processing capabilities. It can be used to write form letters from a mailing list, produce invoices, packing slips, purchase orders, and so on.
Let's look at a sample report form. It's like the screen file for ve: text is outside brackets, and column names are inside brackets. Other commands can also go inside the brackets. Here's a report form for the miist file:
```text
< city >,
```
```text
<1! date +8D I>
Dear < name >,
This is a computer chain letter.
I am also sending it to:
```
```text
"’ | justify 1>
Bye, I>,
```
This yields:
*— PDF-Seite 47 · Buchseite 37 —*
```text
Joe
Main St.
Santa Cruz, CA
09/03/89
Dear Joe:
This is a computer chain letter.
I am also sending it to:
```
```text
name city
Bob Ithaca
Bye, Joe.
```
Arbitrary text goes outside the angle brackets; column names go inside angle brackets. and any arbitrary command or shell program or shell command(s) can go between exclamation marks within angle brackets, and you can still specify columns from the current record therein. You can even have reports within reports ...
Conclusion
In school you learned how to add, subtract, multiply, and divide. On the foundation of those simple operations can be built all the rest of arithmetic. These four operations work on numbers. A relational data base gives you a simple set of operations on tables of information. With column, row, join, and so on you can do enormously powerful things, but you will have to start thinking about what you want in terms of these operations.
Just as the add command does not care if it is adding apples or space shuttles, column does not care what the information in the tables is. Therefore, these commands can manipulate any data. This is an incredibly powerful idea that will take some time to get used to. These relational operations are a well thought out. pretty complete set of all of the things you will want to do with your data. It is up to your imagination to discover all of the powerful, yet quick and easy tricks you can do with these extensions of COHERENT.
*— PDF-Seite 48 · Buchseite 38 —*
*— PDF-Seite 49 · Buchseite 39 —*
# Section 4 — Entering Data into Tables
You have seen how to access your data, now we have to think of how to get your data into the data tables. This is the real work of any data base system, so there are many tools to make data entry as easy as possible.
```text
ve: The Forms Editor
```
ve was created to serve as the principal data entry and data editing system for /rdb data bases. It has much the same interface as the COHERENT text and program editor vi. We wrote it that way so as to minimize the amount of user training required to bring a new data entry person up to speed and to minimize the amount of confusion that could be caused by switching back and forth between the COHERENT text editor vi and the /rdb forms editor ve. Like the vi text editor, ve is a very powerful editor. Unlike vi, however, ve edits data in forms rather than in the free-form manner of vi and ve has optional features you can invoke to check the validity of your entries as you enter data, create an audit trail of your entries (or changes), automatically number your rows, and much, much more. ve also allows you to create /rdb tables directly from the forms editor and has a built in help facility so that you can review any of its features or commands in the middle of your editing session.
ve is called a forms editor. This means that you, the user, have control over the way your screen looks and the placement of the various fields that you will enter data into on the screen. The form definition of your ve screen is defined by a screen file or screen template that you create. To create a screen file use any text editor to set up a one screen form that consists of:
- The labels you want to have on the screen to prompt you for each column, and . The other text or symbols you want on the screen to identify the row.
This procedure is called painting the screen. The labels on your screen are to be followed by the actual names of your columns, enclosed in angle brackets \. This is much the same format that you use to create a report template. For example, if you want to create a telephone list form for data entry, you might create a screen form that looks like
this:
\*\*\*Black Book\*\*\*\*
```text
Name Phone
```
```text
Street
```
```text
city State Zip
```
The column names must be butted up against the left angle bracket. You can have spaces after the column name. Because ve is designed to handle variable length columns (and rows) you don't need to be concerned if the space you leave between the angle brackets in your form isn’t enough to record all the data you plan to put into any particular column. ve will allow you to enter data in columns of variable length. even if you exceed the space available between the brackets on your screen, by shifting the window containing your data if you key in more data than you have space for on the screen. ve also provides a scroll left or right command and a zoom command so that you can see the full text of any column for which there is insufficient space on the screen to display.
*— PDF-Seite 50 · Buchseite 40 —*
Once you have created the screen form. you then create the table by invoking ve. If you tell ve to check the validity of your entries as you enter data into your table (with the -v switch), then ve will prompt you for validation constraints when you create your table. You can then set limits on column size, eligible characters to be keyed in, and table lookups in other tables to cross-check the validity of your entry. These validation constraints can always be modified later, so you do not have to get it perfect the first time.
ve also supports multi-user data entry or editing of the same table. It provides record locking features that will allow you to avoid the problems that could be caused by having two or more users attempting to edit the same row at the same time. With ve’s multi-user record locking, only one user has access to a row at a time. Subsequent requests for a row in use are inhibited, and a message is displayed.
This is a brief and general introduction to forms editing with ve. We have omitted a discussion of the special data security features provided with ve, issues such as protected fields in ve, instructions for optional cursor positioning, a ve command summary, a discussion of the default list screen format, auxiliary indexing, and more. These are covered in a subsequent chapter, in the ve manual pages, and in the on-line help screens of ve.
There are methods for data entry into /rdb tables other than ve.
Text Editor or Word Processor?
enter:
Another simple way to start a data table is to use a text editor or word processor. Type the column head lines and dash lines and the first few rows of your table. Then save it. leave the editor and try some of the query programs to see if you have set it up correctly. See the section on Rules for Table and List File Set up. below.
This approach is good for starting your data bases and for small data bases, but at some point a database may get too large for text editors. Then special purpose programs are needed. Each has its advantages and disadvantages.
## Mass Entry of Data
The enter command is an easy but limited way to type in a lot of data. For example. you or your operators might have to enter card files, or mailing lists, or other bulk data. You may not have time to train them to use a word processor or ve. With the enter program, they just type
```text
enter
```
and the name of the file. The program then prompts them for each column of each row. which they type in. Each new row is simply appended to the table. It lets them go back to an earlier column if they make a mistake. but there is no validation or browsing of the table. It requires the lowest skill level and is the quickest to learn.
```text
update: Update a Table
```
The update program lets you browse through a table file of any size. find a record with fast access methods if you wish, edit the record found with any text editor you like, and return the record to the file where it came from, or append the record to the end of the file if it is too big to fit back in where it came from.
*— PDF-Seite 51 · Buchseite 41 —*
## Programs and Other Formats
Another great thing about COHERENT and /rdb is the ease of converting data files into different formats. The /rdb table and list formats can be converted to and from all of the other data base and word processor formats with simple shell, awk, sed, and other COHERENT program tools. You can use other programs, instruments, computers, tapes. floppy disks, networks, bar-code readers, natural-speech recognizers, expert systems, deep space probes, and more to get your data, then simply transform it into /rdb table and list format and use /rdb commands to do whatever processing you want. There are, therefore, a multitude of ways to get your data in. After processing, you can transform it again and send it back out.
Rules for Table and List File Set up
If you use ve to create and enter your tables you won't have to worry a lot about these rules. But if you don't use ve, you'll need more detail about setting up a data file. Your data is kept in files which can have either of two formats: table or list.
Table Format
A table looks like this:
```text
Name Title Wage
Mary Pres. 4.98
Shawn V.P. 2.98
```
To repeat, there are only three rules for making tables that the /rdb programs can understand. They are:
- There must be a single tab between each column.
- Put a column name, in the first line of the table, at the head of each column. Be sure there is a tab between each column name.
s Put a dashed line as the second line of each table above each column. There must also be a tab between each column's dashes.
- It is best if the dashed line is as wide as the widest string in each column, but it is not necessary.
The justify command will set it to that width for you, if you wish. Remember to use the dash or minus character ‘-’, not the underline character ‘\_'.
There are several ways to make your tables pretty and to handle special problems. These programs all require that you follow the three rules in order to work.
```text
List Format
In addition to table format there is also list format, which looks like this:
```
*— PDF-Seite 52 · Buchseite 42 —*
```text
Name Mary
Title Pres.
Wage 4.98
Name Shawn
Title V.P.
Wage 2.94
```
The rules for lists are similar to those for tables:
The first character of a list-formatted file must be a newline. A newline character is what you get when you hit your \ key. It appears on the screen as a blank line. Be careful that there are no unseen spaces or tabs in this first line that would also look like a blank line, but would confuse the programs into thinking they are looking at a table-formatted file. The programs use this first character to decide the format of the file so they can handle both list and table-formatted files.
The file has exactly two columns. There must be a tab between the column name (i.e., Name) and the value (Mary).
Each row (or record. corresponding to a row in a table) must be separated from the next row by a newline character. It looks like a blank line on the screen. (Note the blank line between Wage [for Mary] and Name [for Shawn] in the list example). There must also be a blank line at the end of the list file. Remember that a blank line has no characters in it. The programs can detect these two newline characters in a row. That is how they know that the end of the row (record) has been reached.
## Tab Problems
The use of tabs to separate columns in /rdb has many advantages, but they create a few problems. The advantages include:
Ease of input. When you press the tab key, the cursor jumps to the next column. This is very natural to typists.
Tabs look nicer in tables then printable characters. They line up columns and are a natural separator.
COHERENT utilities like awk, sort, and others, know about tabs and handle them correctly.
File size. No extra characters are needed to fill out the table (unless the table is justified).
No schema or other special file must be created and maintained to tell the programs where data fields start and end, as is true with most other data base management systems. COBOL programs, for example, are even worse. They have the exact length of each field and record defined at the beginning of their code. This creates extreme inflexibility. If you need to change any of your data, such as making a string longer or adding a column, a COBOL program would have to be modified by a programmer and recompiled. The output of one COBOL program is unacceptable as input to another COBOL program unless the fields and their widths are exactly the same.
Some of the problems and their solutions are as follows:
*— PDF-Seite 53 · Buchseite 43 —*
## Seeing the Tabs
You can see the effect of the tab, but not the tab character itself. So, if you make an input error, how do you know? You should often use the check program. It is especially important for large files. It will report any lines that don’t have the same number of columns (tabs) as the head line. It will also display the line to simplify finding where the missing or extra tabs are located within the row. In most editors there are facilities for seeing “I for every tab on the line or in the table respectively. Outside the editor you can also use the see command or od -c table to see the special characters in the file. The see command turns tab characters into “I. After running od, out comes a strange-looking table showing each character including nonprinting characters converted so that they can be seen. od means octal dump, but the -c option means to convert the bytes of the file into their ASCII character representation. A tab is printed as: \\t. as in the C programming language.
```text
Table-Width Problems
Your screen is usually 80 characters wide. What if a table is wider than that?
```
- Use ve to view your table. Ifa field is wider than the screen, you can shift the field left and right. The default screen format tries to make a multiple column list of each field of a record.
s Use the list format when you create your table. See the manual pages for listtotable and tabletolist commands.
- You might decide simply to live with letting a long row in a table wrap around to the next line on the screen.
- Break the table into two or more smaller tables. You may join them back with the jointable command if you occasionally need to.
®: A table created by jointable, in a pipe, can be up to the maximum character width that your available computer memory will hold.
- You can project only the columns you want to look at from your big table.
- You can get a wider terminal (some are 132 characters wide instead of the standard 80) or printer (some allow compressed print).
## Special Characters
You can use special characters in the column names (in the header lines). but it is best not to. If you do, you will need to put quotation marks (") around the names when you type them at the terminal to protect them from the COHERENT shell. The rules for quotation
marks, on COHERENT shell command lines, are: apostrophes (’...) absolutely protect everything enclosed and quotation marks ("...") protect every character except the dollar sign (8).
Therefore, put apostrophes around the whole string you are passing to row, compute, and validate. Use quotation marks around column names that contain special characters including spaces. For a complex example:
compute ‘"Item#" == 15 { len = length ("col 1") }’ \< table
Note that Item# has a special character in it, and that col 1 has a space in it. All of these must be quoted ("). Also, the entire command must be enclosed within apostrophes (’).
*— PDF-Seite 54 · Buchseite 44 —*
Even when you take these precautions, some COHERENT systems just don't like special characters. It's best not to use them. Limit column names to alphanumerics, don't begin them with numbers, and don't use any of the awk reserved words as column names.
## Data Validation: How To Get Data Right
Data can be validated in many ways and at many times. ve allows you to specify validation constraints at data entry time, checking each entry as it's made to make sure it passes tests on what's allowed and what isn't. There is also a validate command which allows you to specify the conditions that are invalid, and the error message that should print out when the invalid data is found. The validate command is like the row and compute commands. They all pass their instructions on to awk, which does all of the hard work. First a simple example. If you had an inventory table like this:
```text
Item# Onhand Cost Value Description
1 3 50 150 rubber gloves
2 100 x 500 test tubes
a -5 80 -400 clamps
4 23 19 437 plates
5 -99 24 -2376 cleaning cloth
6 89 147 13083 bunsen burners
7 5 175 875 scales
```
There are several invalid values that have gotten into your table. You might want to check that no Onhand item is less than zero. You can type this command:
```text
validate ‘Onhand < 0 {
print "negative Onhand in line " NR
}’ < inventory
```
This yields:
Item# Onhand Cost Value Description
```text
1 3 50 150 rubber gloves
2 100 xX 500 test tubes
```
```text
3 5 80 -400 clamps
negative Onhand in line 3
```
```text
4 23 19 437 plates
negative Onhand in line 5
```
```text
5 ~99 24 -2376 cleaning cloth
6 89 147 13083 bunsen burners
y 5 175 875 scales
```
You can also put the command into a file and call it something like checkinventory. It would then be a shell program that can be run regularly. See the validate command in the manual for more examples and information.
*— PDF-Seite 55 · Buchseite 45 —*
# Section 5 — ve Form and Screen Editor
ve is a table editor designed for use on /rdb tables. Users who are familiar with the vi text editor will enjoy the advantage of understanding ve's mode of operation and will already know most of the ve commands.
This section describes the commands and what they mean, how to set up /rdb tables, how to use the optional features to tailor ve to your application, and other considerations which will help you in both designing and using your tables.
```text
ve Commands
```
Most ve commands are described in detail in the following sections; a complete command reference list is provided in the first ve on-line help page. ve's command language is very much like the command language used by the vi COHERENT editor, in that both editors use regular letters and symbols as commands. As such, the keys you hit are interpreted either as commands to ve or as text that is being entered into your table depending on the mode ve is in when you type them: insert mode or command mode. For a summary of the vi editor, see the COHERENT Lexicon’s entry for elvis, which is COHERENT’s implementation of vi.
Because ve is essentially a visual experience, the best way to understand it is by sitting down at a terminal, creating a ve table, and experimenting with it.
## Moving Around
The following table lists commands that move your cursor to a desired position on the screen. It indicates whether a given command scrolls, if it knows about counts, and if it can be used as a target.
```text
Command Scroll Count Target
no yes no
B no yes yes
1 yes yes yes
h yes yes yes
kj no yes no
“$ yes no yes
G no yes no
HL no no no
wbe yes yes yes
<> yes no no
fF; yes yes yes
```
The following describes each command in detail.
```text
Move the cursor to the next column in top-to-bottom, left-to-right order on your
screen. The key also works in insert mode.
```
*— PDF-Seite 56 · Buchseite 46 —*
B Moves the cursor to the next column in bottom-to-top, right-to-left order on your screen.
```text
1
Move the cursor one character to the right.
```
h Move the cursor one character to the left.
kj The k and j commands move the cursor, respectively, up and down the screen one row.
“$ The \* and § keys move the cursor to, respectively, the beginning and end of the column.
G Move the cursor to the last row in your table. When you precede the G command with a count, ve displays the row in the count position in the table. For example, 100G means “display the 100th row.”
HL The H key moves to the beginning of the first column on the screen; the L key moves to the the beginning of the last column on the screen.
wbe\_ The w key moves the cursor one word to the right: the b command moves the cursor one word to the left; and the e command moves the cursor to the end of the word.
\<\> The \> command scrolls continuously through the column, left to right, until it reaches the end. The \< command scrolls continuously through the column, right to left, until it reaches the beginning.
fF The f command looks left to right from your cursor for the character you specify; the F command looks looks right to left from your cursor for the specified character. The key you hit immediately after typing f or F is assumed to be the character you are seeking. When ve finds the character, your cursor moves to its position in the column. The ; command repeats your last f or F request. It remembers both the character you last found, and the direction in which you were moving.
Occasionally, your screen will not be able to display all the data in a column or row because its width exceeds that of the the screen window. To compensate for this, many movement commands scroll left and right through the data, allowing you to see the entire contents of columns which are too long for the screen space allowed.
Some commands let you to specify how many times ve repeats the command before it repositions the cursor. These counts are entered as a number before the command. For example, the command 41 moves the cursor to the fourth character in the column (left to right). The command 2b moves the cursor two words to the left of your current cursor position.
When ve beeps or flashes at you instead of moving. it means that the command is inappropriate or that your cursor is already at your destination.
## Displaying Your Data
There are two basic methods for displaying data on your screen. One is to display it sequentially, which is the way they appears in the table. The other way is to look for specific rows hy searching the table.
Sequential display: n, - The n (or next) command displays the row in the table that immediately follows the one now displayed. If n is the first command you give ve. it begins at the first row in your table. The - displays the row in the table that immediately precedes the one
*— PDF-Seite 57 · Buchseite 47 —*
now displayed. If - is the first command you give ve, then it begins at the last row in your table. Both sequential display commands wrap around to the beginning/end of your table after the last/first row has been displayed.
Searching: / When you use the / command, ve traverses your table row by row. looking for the pattern you specified. It can repeat a search without making you retype the pattern or character. If you have denied access to some columns by excluding their names from your screen file, ve will omit these columns in its search.
The / command begin its search at the position of your cursor in the row and is complete when the pattern you specify is found or when the entire table has been examined. For example, to search for John Doe in your blackbook table (which is described below), use the command /John Doe. For you to see what you are typing, ve provides the last line of your screen to display the pattern as you type it in. You can use your erase character to edit this line. When you are done typing in the pattern, hit \ or \ to tell ve that you are done. If John Doe is a pattern in your table, then the row which contains John Doe will be displayed on the screen.
Because ve remembers your search pattern, you need only type / and Esc\> or \, to repeat your search of a specified pattern. Each time you enter a search pattern, ve forgets the previous one.
## Getting the Right Row
Usually the only requirement ve enforces when trying to match a search pattern to data is that the entire pattern is contained in a single column, regardless of which column it is or its position in the column.
Sometimes a search pattern will match data in many rows when you are looking for a specific row. Choosing a search pattern which is unique to the row you want displayed will speed up the search process. If this is not possible, you can limit the way ve searches by forcing the pattern to match the beginning or end of a column, or by specifying a particular column to which ve should limit the search.
Position matching: \*, $ The character \*, when it is the first character of a search pattern, tells ve that the pattern following it must match data at the beginning of a column. The character S. when it is the last character of a search pattern, tells ve that the pattern preceding it must match data at the end of a column.
If you are searching for the ‘\* character in the first position of your pattern, or the ‘S' character in the last position of your pattern, you must precede these characters with a backslash (\\).
Search column selection: m, M Another way to limit your search is to make ve search only one column in each row, using the m command. When you mark a specific column to be searched. ve doesn't bother trying to match your search pattern with data in any other column. As such, the search is quicker and the results are more likely to yield the desired row on the first search.
To use the m command, simply position your cursor at the column you want to search and hit m. All subsequent searches will be limited to data in that column only. Hitting the m key on a different column changes the search column to that column.
*— PDF-Seite 58 · Buchseite 48 —*
If you have marked a search column and you want to go back to searching all of the columns in each row, hit the M key to unmark your columns.
Inserting Text
```text
Because most ve commands are ordinary characters, how do you tell when you are
executing a command, and when you are entering text?
```
When you type one of the insert commands listed below. ve switches from command mode to insert mode. When you are in insert mode, everything you type is data and is displayed on your screen. You know you're in insert mode because the \ message is printed at the bottom of your screen. If you don't see that message, then you are in command mode.
The only way to get out of insert mode is to hit the \ key. When you do this, ve erases the insert message at the bottom of the screen and returns to command mode.
Several commands put ve into insert mode. Some commands destroy existing text (indicated by ‘\*’), whereas others add to it. All of the commands except O take effect on the column at which your cursor is positioned, and, with the exception of the o command, at the actual position of your cursor in the column. The C, c, and s commands mark your text with a $ symbol to show you the text that will be changed. This symbol disappears when you type over it. or when you hit the \ key from insert mode.
The r or replace command is the only command which substitutes text without entering insert mode. To use the r command, position your cursor at the character in the column you wish to change, type r and the character to replace it. The r command can be used with counts. For example, to replace the next four characters with the letter ‘x’, use the command 4rx.
Command Means
```text
a Append text to the right of the cursor
```
A Append text at the end of the column
```text
i Insert text to the left of the cursor
```
I Insert text at the beginning of the column
```text
o* Open the column and insert text at the beginning
oO Open a blank row
```
ctarget\* Change the text between the cursor and target
```text
c Change text from the cursor to the end of the column
s* Substitute the character at the cursor for text
```
```text
R* Replace (overwrite) text character by character
Deleting Text
```
The delete commands let you delete entire rows and columns, partial columns, or characters from your table:
Command Means
```text
dd Delete the entire row
```
```text
D Delete text from the cursor to the end of the column
x Delete the character(s) at the cursor
```
dtarget Delete text from the cursor to target
The x command also knows about counts.
*— PDF-Seite 59 · Buchseite 49 —*
Targets
The insert command c and the delete command d require that you specify a target. A target is exactly what it implies — a destination for the command being executed. Commands that can be used as targets are listed in the section on moving around, The table below shows sample d and c commands and what they mean when used with different targets.
Command Means
3dw Delete the next three words
```text
de Delete to the end of the word
```
ce2fg Change the text to the second g found moving right
c\* Change the text to the beginning of the column
cS Change the text to the end of the column
d; Delete text to character specified by last f or F command
All targets assume that the delete or change action begins from the position of the cursor and counts must be specified before the actual target.
## Yank, Put, and Undo
Sometimes accidents will happen when you are editing — you will hit the wrong key, or decide that you really don't like a modification. You may even delete an entire row and then realize it shouldn't have been deleted. Or perhaps you are entering rows which are almost identical and you are sick of typing in the same thing over and over again. ve has a number of commands that help you to efficiently deal with a change of mind after a change of text. mistakes and repetitive data entry. These commands are known as yank, put and undo commands.
Yank commands copy data from the row displayed on the screen into a special buffer. Put commands put the yanked data from the buffer into the row on the screen.
Yanking data does not alter the row from which it is copied. Generally, once data has been yanked, it can be put indefinitely without having to yank it again. Because ve remembers only the text last yanked for each column displayed, yanking data from the same column in another row overwrites previously yanked data in that column with the text that is currently displayed. When entire rows are yanked or deleted, all yanked columns are overwritten with the text in the displayed row.
Selected columns are yanked with the y command. To use it, position your cursor on the column you want to yank and hit the y key. Different columns may be yanked from different rows.
All columns on the screen can be yanked with the Y command, and it works by hitting the Y key from any position on the screen.
Putting data replaces the data in the row or column being displayed with the data last yanked by a y. Y, or dd command. Data can be put only in columns from which it was yanked. For example. you can't yank text from a phone number column and put it in a customer name column.
The p command replaces the data in the column at which your cursor is positioned with data that has previously been yanked from that column.
The P command replaces the data in all columns currently displayed with data that has previously been yanked from each column. Since veconsiders deleted rows to be yanked text, using the P command after mistakenly deleting a row will restore it.
*— PDF-Seite 60 · Buchseite 50 —*
ve remembers the data in the last column modified prior to the last command which modified it. You can restore the data to that state by hitting the u key. The u command works only for undo-ing modifications made to the row currently being displayed, and will not undo what's already been undone.
## For Your Information
The # command displays the list of topics in the on-line ve help files available for perusal. To select a help file. position your cursor at the ==\> symbol to the left of the desired topic by using the J. \, -, and k keys to move down and up the list. Then, hit any other key (except q) to view your selection a page at a time. The J and \ keys display successive pages, and the - and k keys display previous pages. Any other key (except the q key) returns to the table of contents. Hit the q key to get back to your data display.
Other commands which provide assistance with or information about the current screen contents:
- The v command displays the validation requirements for the column on which your cursor is positioned.
e The t command prints the look-up table for the column upon which your cursor is positioned, if such a table exists.
- Use the S command to redraw your screen if your deta display gets messed up.
® The z command draws a window under the column your cursor is on and displays the contents of the column in the window. This command comes in handy when the data for a particular column does not fit in the screen space allowed. The next key you hit will erase the window.
## Writing Rows
Whenever you change the data by adding or changing a row or column, you must use a W or ZZ write command to make your changes or additions part of your table. When you use the W or ZZ command, ve re-checks the data to make sure that all validation tests (if any) have been passed.
When you are using the W command, and the data does not pass your validation tests (if any). ve will complain and refuse to write your row in the table. In this case. your cursor will land on the column which contains the bad data and you can fix it. If there are no tests, or when the data passes your tests, ve will write your row in the table. and await your next command.
The ZZ command is a quick way to write your row and exit from ve. If the row on the screen has been added or modified and it passes your validation tests (if any), ve will put it in the table before quitting. It will not tell you whether or not it writes the row.
If your data has been changed and you attempt to display a different row with a before using the W command, ve will warn you that the row has not yet been written. Repeating the command will override the warning, and the row on your screen will not be written in your table.
*— PDF-Seite 61 · Buchseite 51 —*
## Getting Back to COHERENT
There are two kinds of commands which will get you back to COHERENT: shell commands (!,%) and quit commands (q,ZZ). Shell commands let you talk to a new COHERENT shell while your ve process is suspended in the background, waiting for you to return. Quit commands end the ve process and return you to your COHERENT shell.
The % command displays a % symbol at the bottom of your screen and puts ve into suspended animation. When you see your login prompt appear at the bottom of the screen, COHERENT is ready for your command. To resume your conversation with ve, hit \ (your EOF character). If you are not familiar with COHERENT processes and shells, remember that it is easy to get carried away with COHERENT and forget that ve is still patiently waiting for your return. You will know something odd is happening when you try to log out and COHERENT keeps saying not your login shell. You must first return to ve and give it a proper quit command. If COHERENT still complains, it means that you have repeated the % command a succession of times. and you must repeat the \q sequence until you can log out.
The ! command before a COHERENT command executes the COHERENT command at the bottom of the screen and then immediately return to ve. To read the results of your COHERENT command, the message
```text
[Hit RETURN to continue]
```
appears and ve awaits your response before it redraws your screen. The "%’ symbol, when used in the ‘!' form of the shell command, is replaced with the name of the table you are currently editing. To repeat a ! command. type !!.
## Quit Commands
When you are finished using ve, you can use the q or ZZ command to exit. The only difference between the q and ZZ commands is that q complains if the row on the screen has not been written after a modification has been made. (A second q command simply exits without writing the row.) The ZZ command will automatically write your row before exiting ve.
## Colon Commands
People accustomed to using the COHERENT editor vi are already familiar with colon commands. Colon commands are always preceded by a colon (:). When the colon key is hit. it appears at the bottom of the screen and the remainder of the command appears next to the colon as you type it. You must enter at least the first letter of the colon command for it to work (letters enclosed in [ ]'s show how much of the command you don't need to type). You must end colon commands with \ or \ to let ve know you are done.
```text
Colon Command Is the Same As Described in Section
:nfext] n Sequential Display
:o[pen] °o Inserting Text
```
```text
thfelp] # For Your Information
:wirite] Ww Writing Rows
```
```text
:s[hell] % Shell Commands
s!command, !! ! Shell Commands
:q(uit] q Quit Commands
```
*— PDF-Seite 62 · Buchseite 52 —*
Macros
A macro command is defined as one or more ve or COHERENT shell commands mapped to a single control key. Each time the control key is hit, the command or sequence of commands defined by that control key will be executed.
Macro commands can be used to simplify an often-repeated sequence of commands into a single keystroke. Because control keys are non-printable characters and cannot be confused with potential data (unlike regular ve commands), they work from both command mode and insert mode. The mode from which you execute the macro is restored after successful completion of all the commands which define it. It is even possible to design a set of macro commands that makes ve appear to be a single-mode editor. This might be desirable for beginning users who find two edit modes confusing.
A maximum of 23 macro commands may be defined for the \ through \ keys. If your erase character or your interrupt character is a control key in this range, then it (they) are excluded from the list of control keys available for macros. Macro commands that include a second macro in their list of commands will replace whatever commands follow the second macro in the list with the list of commands in the second macro. Embedding macros in macros is confusing and it is not recommended.
Macro definitions are stored in a ve table named .verc. If you want to define your own macros, this file must be in your home directory where it can be shared by all ve tables in your account. If you don't have your own .verc file, ve will use its own.
The first column in the .vere file contains the letter which is hit simultaneously with the control key to make the control key code. The second column in the .vere file is the command or commands that are executed when the that key is hit. Four non-printable commands which you may want to use in your macros are \, \, \, and \. They should be indicated by \\t. \\e, \\m, and \\b, respectively. Below is a copy of the default .verc file ve uses.
```text
Control Key Command
#
ddn
°
ZZ
s
%
t
Ww
```
For example, let's say we're editing the blackbook table and we forgot to type in the area codes for local phone numbers with 429 prefixes. If we mark the phone column using the m command, and the macro
```text
Pp /*429\e1 (408) \ew
```
```text
reonQonp
```
is a row in our .verc file, then every time we hit \, ve finds rows in which the first three characters of the phone column are 429. ve will then insert (408) at the beginning of the column and write the row.
*— PDF-Seite 63 · Buchseite 53 —*
## Shell Macros
If the command column in the .vere table begins with ‘!, then the remainder of the command column, up to the end of the column or another ‘!’, is passed directly to the shell. If the command contains valid column names enclosed in ‘\<' and ‘\>’, then the contents of the named column(s) currently displayed on the screen will be substituted before the shell is called.
Using the blackbook table, let's add a macro which will dial the emergency phone number when we hit \:
```text
e tdial \n
Like regular shell commands, shell macros also expand ‘%' to the name of the current table.
```
For example, let's say we have a subdirectory named Personnel containing text files about each employee in the personnel table. To keep these files distinct and unique, each is named by the Social-Security number of the employee. See if you can figure out what the following shell macro will do:
```text
g Icat ‘echo % | cap‘/\n
```
ve will echo the interpreted shell command on the message line, send it to the shell for execution, and then print the
```text
[Hit RETURN to continue]
```
message before refreshing your ve screen. Placing a ‘-' after the ‘!’ in the shell command line will suppress the command echo, the pause and the screen refresh.
To see a list of the .verc commands in effect while you are using ve, hit \.
## The Command Line
The files ve uses and the way it displays and formats your data are determined by entering a single command line at the prompt. The syntax for ve is:
ve [data [ -s [file] -h [file] -a [file] -v [file] -n[n] -fce -me -i]] [-b]
Dashes which are followed by a single letter are called switches (-s, -h, -a, -v, -m, -m, -i, -b). Each switch tells ve to perform a specific job when it is invoked.
Words, symbols, and letters that directly follow each switch, when substituted for file names, numbers, and characters, further define how ve should do the job indicated by the switch. The word data shows where you would type in the name of your table; the file words show where you would substitute the names of any files you might use. The n symbol shows where you would substitute a number, and the c (as in -fc or -mc) shows where you would put a letter or character.
The brackets ([ ]) are used to indicate items on the command line that are optional, and should not be used in an actual command line. Note that with the exception of the word ve, everything on the command line is optional. Thus, the command
```text
ve
```
is a perfectly valid ve command that displays the on-line help file index.
*— PDF-Seite 64 · Buchseite 54 —*
## File Options
The first four switches in the command line apply to files that, with the exception of the screen file, are in /rdb table format. They let the user define how the screen displays the data (-s), separate the header lines from the data rows (-h), keep track of each modification made to the table (-a), and impose various restrictions on the data as it is entered (-v). Each of these switches can be used with the name of a file.
## File Creation
How do we use the file options when the table or the files don't exist? The best and simplest way is to let ve create, format and store the necessary files. This can be done in a single command, so that all files are created and initialized at the same time. The following table shows the conditions under which each type of file is created:
```text
ve will create When
```
The table There is a screen or a header file
The header file There is a screen file and no table
```text
The audit file There is a screen or a data or a header file
The validation file There is a screen or a data or a header file
The screen file Never — the user must do this
```
By examining the table above, it is apparent that the only file ve really needs in order to create all of the other files, including the table, is a screen file. The preferred method for initializing a ve table (starting up from scratch with no files), is:
A. Create a screen file. making sure to include all of the column names you want to be
```text
part of your table.
B. On the ve command line, type in:
x The name of your table,
2. the -s switch with the name of the screen file you've just created,
3. and A file option switch followed by a name for each file you wish ve to
create.
```
For example, let's say we want to create a table named blackbook. Also, we want to impose certain limitations on how the data is entered in some of the columns, and put these limitations in a validation file called limits. So far, neither of these files exist.
The first thing we do is create a screen file which we name display. In the display file, we include all of the column names we want in our blackbook table. When we finish making our screen file, and type in the command
```text
ve blackbook -s display -v limits
the following steps are performed:
```
A. ve looks in the blackbook file for the header rows. But blackbook doesn’t exist, so ve creates it.
B. ve then reads the screen file we have created named display. It creates the header rows from the column names in the screen file, and puts them in the new blackbook table.
*— PDF-Seite 65 · Buchseite 55 —*
C. ve creates a validation file named limits and uses the column names in the first header row to create the rows in limits.
When ve is finished making all the new files, it draws your screen according to the display screen file, and puts you in ve edit mode, exactly as if the files had already existed before issuing the ve command.
Typing in the ve command line can be time consuming and tedious when using the file option switches, especially if you are using any of the other switches as well. ve has a builtin method of naming optional files associated with a table. When you take advantage of this feature, the command line is greatly simplified.
## Using the Default File Names
Whenever a ve command is issued with the name of a table, ve looks for files with names that begin with the name of the table and end with each of the four file option switches. These files are called default files. or files which are used by ve in the absence of specified files. For example, consider the table named blackbook:
```text
File Switch File Type ve Looks For
-s Screen blackbook-s
-v Validation blackbook-v
-a Audit blackbook-a
-h Header blackbook-h
```
If any of the default files exist. ve automatically includes them in the command line.
Specifying a file option switch with a file name overrides ve's inclusion of the existing default file in the command line. As a corollary to this, files that are to be included in the ve editing session which do not have default names must always be typed in the command line, following the appropriate file option switch. For example, suppose you want to use a screen file named myscreen instead of the default screen file named blackbook-s:
```text
ve blackbook -s myscreen
```
Creating files from scratch also becomes much easier when using the default ve file names. The same rules apply as above for creating files, but the names of the files do not need to be typed in. Let's assume that we are starting out fresh with no files. We want to start a new table named blackbook, with a validation file and an audit file. If we create a screen file and name it blackbook-s, then the command line
```text
ve blackbook -v
```
is all that is necessary to create the table named blackbook, and the validation file named blackbook-v.
## Automatic Row Numbering (-n)
The -n switch tells ve to give each row a unique numerical identifier automatically as it is written. ve looks for and stores this number in the first column of each row.
If you are initializing a new table and you use the -n switch, you must reserve the first column for this number. Of course, you may name the column anything you like — it just has to be there. ve will start the row numbering at one.
*— PDF-Seite 66 · Buchseite 56 —*
If your table already exists, ve figures out what to number new rows by scanning the first column of each row in the table and adding one to the largest number it finds.
The n option to the -n switch, when substituted with a number, tells ve to start new rows with that number. If the number you specify is less than the greatest numbered row in your table, ve simply ignores your request, since it would mean duplicating existing row numbers.
Once the -n switch has been specified in the command line for a particular table. it is not necessary on subsequent calls to ve to include -n in the command line (unless you are resetting the number with the n option), since ve keeps track of the largest numbered row. The command
```text
ve blackbook -n2001
```
is an example of using the -n switch to invoke automatic row numbering beginning with
2001. When you are editing a table that uses automatic row numbering. and the first column is displayed on the screen, your cursor will not land on it. This is ve’s way of making sure that you don't mess it up.
## Start-up Mode Specification
The -m switch tells ve to enter the editing session in a particular mode. This mode is specified by a character which must follow the -m switch, and can be i for insert mode, / for search mode, or n for next mode. ve will return to this mode whenever a row is written. If, for example, we want ve to start up in the insert mode, we would use the command:
```text
ve blackbook -mi
```
## Initialization Option
ve creates and maintains an index of the rows in your table. During ve edit sessions. this index keeps track of which rows are being accessed by other users and which rows have been deleted. When the table is quiet. ve uses the index to clean up the table by removing the deleted rows and putting the updated rows in order. The index is also used to store the last automatic row number (if applicable) and the column separation used by your table.
If your table has been modified using using a method other than ve, the index must be recreated. This is done with the -i switch, which means initialize the table. It is not necessary to use the -i option when you are creating the table.
## The Screen File
A screen file is an ordinary text file which is created with any editor. It visually describes the way the data are displayed during a ve edit session. If there is no screen file, ve displays your column names in columns on the screen with the corresponding data adjacent to the name. There are several reasons for using a custom screen file:
```text
° It is the simplest and most accurate way to create your table.
° It allows you to take advantage of ve's security features.
```
. It allows you to customize or expand your column labels and helps to make your screen display match specific hard copy forms.
- It allows you to rearrange the order or placement of your column names to accommodate the size of data in the column.
*— PDF-Seite 67 · Buchseite 57 —*
C it allows you to set the column on which your cursor will land each time a row is displayed.
## Screen File Format
The screen file should be formatted to look the way you want ve to display your data. Use the following guidelines when creating a screen file:
A. For each column, indicate the beginning and ending positions for data display in the screen file with the ‘\<' and ‘\>’ angle brackets, respectively. Both brackets must appear on the same line. Type the name of the column between the brackets. If ve identifies text surrounded by \<\>’s to be a valid column name, then data in that column will be displayed between the brackets, and the brackets themselves will become blank.
B. If you are using the screen file to create a table, keep in mind that the names of all columns must be included in the screen file. and that their top-to-bottom, left-to-right order on the screen will determine the order in which ve arranges your data. (This consideration is usually important only when you are planning to use automatic row numbering or an audit file with your table. In that case, the uppermost, leftmost column name will be assumed to be the name of the number column.)
If your table already exists, you must be sure that the column names in the screen file are identical to those listed in the first header row of the table.
C. The entire screen file should be no longer than 23 lines and no wider than 80 characters, since this is the most information that standard screens accommodate (the 24th line is reserved by ve for messages).
Here is the screen file for our address-book table (blackbook):
\*\*\* Black Book \*\*\*
```text
Name: number:
Address:
City/State/Zip: / /
```
## Protecting Columns
Once a table has been created, a screen file can be used to selectively protect specific columns by denying or limiting access to those columns. When you ve a table with a screen file, only the data for columns which are named in the screen file will be displayed. Thus, the simple omission of the names of confidential columns in the screen file protects those columns from being displayed. Data in columns not named in the screen file are also excluded from searching.
This feature comes in handy when you want to use ve to edit a specific subset of columns and do not need to see the entire row.
By limiting access, we mean simply disallowing modification of designated columns. In the screen file, column names preceded by an exclamation point (!) indicate to ve that they cannot be modified.
To illustrate the security features, let's use the personnel table described earlier. For the sake of this example. we'll add two columns for the name of the person to contact in an emergency, and the phone number of that person. The header rows for such a table look like this:
*— PDF-Seite 68 · Buchseite 58 —*
employee ss number emp. date salary emergency phone
Let's assume that this table exists. and we simply want to update it. We want to be able to search for employees by their name or their Social Security number, but we don't want these columns modified. Also, because the salary column is confidential. we don't want it displayed at all. Our screen file might look like this:
Company X-Y-Z Employee Information Card
```text
Employee !
Social Security ! Date employed
```
In case of emergency \ number \
## Setting the Cursor
Unless you are searching for a particular pattern, ve will position the cursor at the uppermost, leftmost column name on the screen.
The column name on which your cursor automatically lands can be changed by preceding the desired column name with an asterisk (‘\*’). For example, if we were updating the emergency name and phone number columns in the personnel table, we could make the cursor land automatically on the emergency column as each row is displayed, by changing the last line of the screen file to look like this:
In case of emergency \*\ number \
## The Validation File
A validation file describes column-by-column requirements that data must meet as it is entered in the table. There are three different kinds of tests that you may force your data to pass before allowing it to become part of your table: character range specification, column length restriction, and table look-up.
```text
Validation File Format
The validation file is a regular ve table. The header rows look like this:
name characters length table
```
For each column in your table which must pass one or more validation test. there is a row in the validation file. The first column of each row in the validation file contains the name of the table column.
## Validation File Creation
ve can create your validation file, but you must supply the validation parameters. To make this task easie;, ve calls on itself to edit the validation file, before opening up and displaying your table.
*— PDF-Seite 69 · Buchseite 59 —*
If you don't want to make a column pass validation tests, simply delete the row which contains the column name from the validation file. When you are finished editing your validation file with ve, your table will be displayed on the screen, and the validation parameters will take effect immediately.
## Character Range Specification
This validation option allows you to specify exactly which characters are acceptable (or not acceptable) in a named column. For example, the ss number column of the personnel table should be comprised of numbers and dashes. The employee column can be letters (upper case and lower case), dashes, periods, commas, and blanks. The zip column of the blackbook table must be numbers only.
ve allows you to specify these parameters in terms of ranges, or as single characters, in the second column of your validation file. A range is defined as a low limit character and a high limit character separated by a dash ‘-’". When more than one characters or range of characters are specified, they are separated by a comma ‘,’. Using the above examples, the character specifications for ss number is ‘0-9,-'; for employee is ‘A-Z,a-z, .-.,..'; for zip is ‘O- 9.
Let's say we have a column which can contain anything except upper case letters:
BZ O-9, Fy pepo tote Le mete Semele dele) hehe BSH Or Label ome om
The ‘!’ symbol, when it precedes a range or character, means not this range, or not this character. Sometimes, as in the example above, the ‘!’ syntax can greatly simplify the parameter list: ‘!A-Z’.
The ‘!’ can also be used to exclude specific members of a range. For example, one way to specify all numbers except 8 is:
```text
0,1,2,3,4,5,6,7,9
A simpler way is:
0-9,18
```
## Column Length Restrictions
ve looks at the third column in each row of the validation file for column length limits. These limits are used for several reasons. For example, we know that zipcodes should be exactly five numbers long. We know that Social-Security numbers are exactly 11 characters. Data entered in these columns which are not the proper length make them meaningless.
Also, it is sometimes the case that other limits indicate the necessity for a column-length restriction. If, for example, we use the blackbook table to produce labels, then we should restrict the length of the columns in the table to conform to the size of the labels.
Another use of column length might apply when you want to force a column to contain data, but you don’t care (or don’t know) what the length should be. For example, in the date column of the personnel table, you might require that something be entered, but it might be of indeterminate length (October 1981. 10/1/81. 10/81, etc.).
Four specifications describe exactly how ve should pass data for the column length test:
*— PDF-Seite 70 · Buchseite 60 —*
```text
=n The column length must be exactly equal to n
n The column length must be greater than n
```
! The column can be blank (length 0)
Using the above examples, the column length for zip column in the blackbook table is =5, which means exactly equal to five characters. If the size of our labels is 32 characters, then the column length for the name and street columns of the blackbook table is \<33, which means less than 33 characters. The column length for the date column of the personnel table might be \>O0, which means there must be at least one character in this column.
When more than one of these specifications is used, they are separated by a comma ‘,’. The ‘Y column length specification, when used in conjunction with other specifications, tells ve to ignore other length specifications if the column is blank. For example, if you specify the zip column length mentioned above to be !,=5, then ve will allow you to skip over that column — however, if you enter any data in this column, ve will force you to make it exactly five characters long.
You can also indicate column length ranges by using the \< and \> specifications together. (In fact, another way of saying !,=5 is !,\<6,\>4.) In the personnel table, the least number of characters needed to specify date is four (1/82); the greatest number is 18 (September 11. 1949). You may wish to place an upper limit on this column simply to preclude the user from typing in something silly like, “Gosh, I don't know, I guess Bud joined the firm round about September, a few years back, because I first met him at the company’s Labor Day barbeque.” In any case, the specification is \>3,\<19, which means any data in this column must have more than three characters and less than nineteen characters.
## Look-Up Tables
The fourth column in the validation file is for the name of a look-up table. If you use table look-up validation on a particular column, then each time you enter data in that column, ve compares it with data in the table. ve makes this comparison based on how you specify the name of the table: if it is preceded by ‘!’, then it passes the table look-up test only if it is not in the table; otherwise, it passes only if it is in the table.
ve updates all tables created from a table as you change, delete, and add data to columns in that table. As such, you need to create each table only once. As long as you always use ve to maintain your table, your tables will be current.
## Table Creation
The vindex command is used to create look-up tables. To use vindex to create a new lookup table (or overwrite an existing one), you must specify the name of the table and the names of the columns in the table you want to index.
For example, if we want to create look-up tables for the ss number and the employee columns of the personnel table, we would use the command:
```text
vindex personnel employee "ss number"
```
vindex creates two files for each table it makes. using the naming convention column-A and column-B. If the name of the column you are vindexing is longer than 14 characters, it will be truncated to 14 characters before the -A and -B extensions are appended to the resulting index files. Spaces are converted to ‘' and special characters which may be part of the
column name are omitted. In this example, the index files for the ss number table would be named ss\_number-A and ss\_number-B. The ss number table is referred to in the
*— PDF-Seite 71 · Buchseite 61 —*
validation file simply as ss\_number.
## Decode Columns
An optional feature when creating and using look-up tables is the cross-indexing capability. When you are creating a table for a column in a table, you can select a second column which should be displayed when your data matches a pattern in the table. The displayed data is called a decode column. The decode column must also be in the table, and, because each indexed or key column can have only one associated decode column, vindex assumes that data in the key column is unique. Similarly, when ve is used to update tables which contain decode columns, the contents of the key column must be unique.
For example, consider the following states table:
```text
state code name
```
NY New York
```text
CA California
MA Massachusetts
```
In each row of the states table, the state code column contains a standard state abbreviation: the name column contains the name of the state that corresponds to the abbreviation. To create a look-up table on the state code column and cross-index the name column, we use the command:
```text
vindex states "state code" : name
```
The colon \*:’ character in the command above is used to indicate that the following column name (name) is a decode column for the column name preceding the colon (state code).
## Unique Columns
We can use the ss\_number table created previously to illustrate the use of look-up tables to enforce unique column entries. In order to make sure that we don't enter duplicate employee rows, we can make ve check each Social Security number as it is entered against a table of those already in the table by specifying the name of the look-up table in the fourth column of the validation row for ss number, using the ‘!’ symbol:
```text
name characters length table
```
```text
ss number 0-9,- 1,=11 !ss_number
```
In this case, the column passes the test if ve does not find an identical Social Security number in the table. When we are editing the personnel table using ve, each time we add a new Social Security number ve will look it up in the table: if it's already there, ve will complain; otherwise, ve will add the new number to the table.
## Column Inclusion
The blackbook table will illustrate how table validation can be used to make sure that the data we enter in the st column are included in a table which lists all of the standard state abbreviations.
We specify the name of the State\_code look-up table in the blackbook validation file. Each time we enter a state abbreviation in the st column of the blackbook table, ve will look it up in the State\_code table. If it's there, ve will print the name of the state next to the abbreviation.
*— PDF-Seite 72 · Buchseite 62 —*
```text
name characters length table
```
```text
st A-2 =2 State_code
```
## Multi-User Considerations
ve is a multi-user table editor. This means that any number of users can be entering or editing data in the same table at the same time. When a row is displayed on your screen, it belongs to you until you release it by moving to another row, writing the row. or deleting it. That means that anyone else who may be using the table at the same time will be prevented from viewing or editing that row until you are finished with it.
Because ve knows which rows are in use at any given time. you will sometimes see the message
1 other match(es) currently in use
when you search for a pattern in a row which belongs to someone else. This is to let you know that the pattern is in your table, but the row which contains the pattern simply isn't available.
When you use a sequential display command (n, -), ve will skip over rows which belong to other users until it finds a free one. When ve has to skip over rows, it will let you know how many. Similarly, the G command will let you know that it can't land ona specified row because either it is currently in use or it has been deleted during the edit session.
```text
/rdb-ve Compatibility
```
If you are planning to use /rdb on tables that are created and maintained by ve, taking the following precautions when setting up your tables will help you avoid trouble later on.
Because many /rdb commands use table column names as command line arguments, care must be taken to exclude symbols or words which have special meaning to the shell from your column names. Specifically, stay away from the ‘|’, '#', and ‘!’ characters; if column names can be confused with shell commands (ie., date, who), remember to protect them from shell interpretation by enclosing them in quotes (") when you use them as arguments to /rdb commands.
When using ve in a shell script, care must be taken not to access the original file until ve is done with it. You can check for this by testing for the existence of a data+lck file. If the data+ick exists, wait until it's gone.
Some /rdb commands use the awk program. which has its own command language. Below is a list of awk words which should not be used as column names:
```text
BEGIN exit in next sqrt
break exp index print substr
continue for int printf while
else getline length split
```
END bib log sprintf
*— PDF-Seite 73 · Buchseite 63 —*
Limits
Two basic size limits imposed by ve are the the maximum number of columns and the maximum number of characters or bytes in each row. On the COHERENT installation, the maximum number of columns is 66 and the maximum row length is 2,048 bytes.
ve will be able to accommodate most tables. If you need more than 66 columns in a row we recommend that you create two separate tables, each with a common column, and use the jointable command to merge the two tables after data entry has been completed.
There are no limits on the number of rows in your table or on the size of columns within a row, as long as the 2,048 byte per row limit is not exceeded.
If you use the look-up table validation feature, you should be aware that a 64-byte limit is imposed by truncation for the the lengths of the key and decode columns.
```text
ve Validation
```
The validation table is used to specify, column by column, requirements that data must meet as they are entered into the data table by associating a shell-level command with the name of the column to be validated.
By default. all columns with associated validation commands are tested when the column contents change or when the record is written, by executing the associated command and using its return status to determine success or failure. A non-zero return status means the test failed. ve will beep and the cursor will remain at the column until the contents are modified to comply with the validation requirements.
Unless the # symbol precedes the command, the command is also executed whenever the cursor passes through the field. unless nothing has changed since the last time the field was passed. However, if the ‘@' symbol precedes the command in the validation file, the command is executed even if nothing has changed. If the ‘#’ symbol precedes the command. the command is executed only when the record is written (or deleted).
Unless the command is preceded by ‘“—’, the exit status of the command determines whether the data in the field pass the validation test.
The shell that executes the validation command has some variables and constructs made known to it by ve. Fields from the current record are passed to the validation command by enclosing the field name in angle brackets, as in the screen file. The construct \<@field\> is used to denote the contents of a field when the record was first displayed on the screen, before any changes were made to it. The ‘%' symbol in the command line expands to the current file name; the shell variables $ROW and SCOL are defined in the environment for the executed shell to correspond to the start position of the current field, and SCOLEND is defined as the first available white space after the field.
The validation file is a table with two columns:
```text
column command
```
The first characters of the ‘command’ column have special meaning:
@ This tneans execute the command even if nothing in it changes This is typically used in conjunction with the ‘!' prefix, to put something into the field without having the operator type it in, like the date.
*— PDF-Seite 74 · Buchseite 64 —*
\_ This means ignore the exit status of the command and always pass validation. This is used when the command to be executed doesn't really have anything to do with validation. For example, it can be used to pop up a new window and display an
e. The window might be thrown away, producing a “fail” exit status, but we really don't care,
! This means replace the field contents with the output of the command and can be used to force the output of the date command into a field, or to calculate a field based on one or more other fields.
```text
# This indicates that the command should only be executed only when the record is
written or deleted, and not when the field is merely changed or passed through.
```
The standard error of the validation command is sent to the status line of the ve screen, so you can customize the error message to include the field being validated or other arguments passed to the validation command.
These commands used to be called “user exits” when this technique was used on IBM systems.
Here's a sample validation file for the inventory file:
```text
name command
```
```text
number lookup inventory $ROW $COLEND
Item unique Item % -
```
```text
Amount. valid.chars "[0-9]"
```
Value @techo "2k \ \ \* 1.25 \*p" | dc
This validation file looks complicated, but only because it's used to give examples of what we've discussed. Suppose we want to look up the description for an inventory item, and place it next to the record number. The first field, number, is validated by running the program lookup with four arguments: first, the file name in which we want to look; \ is replaced by the contents of the number field, and $ROW and S$COLEND become the location on the screen of the first available white space after the viewable window over the number field as specified in the screen file. Bear in mind that SCOLEND becomes the last column on the screen if there's no screen file, so it shouldn't be used without a screen file.
The lookup program moves the cursor to the specified position and prints the Description field:
```text
#1/bin/sh
```
```text
FILE=$1 NUMBER=$2 ROW=$3 COLEND=$4
cursor $ROW $COLEND
```
```text
echo $NUMBER |
```
```text
search -ms $FILE number |
```
```text
column Description |
```
```text
headoff
```
This guarantees uniqueness. Here's the unique program:
*— PDF-Seite 75 · Buchseite 65 —*
```text
#1/bin/sh
```
```text
COLUMN=$1 FILE=$2 VALUE=$3 NUMBER=$4
```
```text
FAIL=1 SUCCESS=0
```
```text
exec 1>&2
```
```text
if test -z "$VALUE"
```
```text
then
echo -n $COLUMN may not be empty
exit $FAIL
```
```text
fi
```
```text
FOUND=‘row "$COLUMN == \"$VALUE\" && number != $NUMBER" < $FILE | \
column number | headoff’
```
```text
if test ! -z "$FOUND"
```
```text
then
echo -n “DUPLICATE $COLUMN $VALUE in $FILE (number $FOUND)"
exit $FAIL
```
```text
fi
```
```text
exit $SUCCESS
```
In all these commands, the standard error is directed to the status line. That's the purpose of redirecting the standard output to the standard error with the first exec command. The algorithm to determine uniqueness looks to see that there's no other record with this value besides the current one.
One of the most common validation procedures is to limit the allowable characters. The following script accepts a string to test. and a regular expression in the standard form expected by the tr command of valid characters:
```text
#1/bin/sh
exec 1>&2
VALUE="$1"; RE="$2"
```
```text
SUCCESS=0 FAIL=1
LEFT=‘echo $VALUE | tr -d "$RE"’
```
```text
if test -z "$LEFT"
```
```text
then
exit $SUCCESS
else
echo $LEFT from $VALUE is not “$RE"“
exit $FAIL
fi.
```
The effect of this command is to delete the allowable characters from the field, and if there's anything left over, they must be invalid characters, and the script exits with a FAIL status. Similarly, the script for specifying invalid characters deletes the complement of the invalid characters (the ones that are not invalid), and if there's anything left over exits with a FAIL status.
The validation command for the Value column runs the de command to calculate Value on the basis of Amount and Cost, putting the calculated result into the field. This is how you compute one field based on the value of one or more others.
*— PDF-Seite 76 · Buchseite 66 —*
To illustrate how the ‘#' can be used in the validation file, let's consider the case where we need to update other tables /f and only if we actually make a change in the current table — say for auditing purposes. Certainly we do not want to have to check each field as we pass through it — it is costly and there is no guarantee that the user will commit the changes made on the screen to the table. We only know and can only timestamp and record changes as the user make that commitment by writing the row. Therefore, we use the ‘#’ validation key, which wakes up and performs the indicated operations only when records are committed (changed. deleted, or added) to the disk. Because auditing does not apply to a particular column, we can link it to any column in the validation file that doesn’t require other validation.
We'll use a customers table as an example and we'll keep track of changes in contacts and their phone numbers. First, the table layout:
cust\_id name company street city st zip phone
And its verification table:
```text
column command
```
```text
cust_id @lookup customer ""
```
```text
name #audit hist o "<@name>" "<€phone>"; audit hist n "" ""
company #putkey customer “" "“<@cust_id>" ""
```
```text
city texchange “" “Santa Cruz"
```
```text
st @lookup st ""
```
The audit command takes an output file name argument (hist), an initial key argument, (o for old values and n for new values), and selected columns to be recorded. Thus, whenever we write a row, audit gets the o key and the original contents of the name and phone columns; then we hand audit an n key, with the current contents of the name and phone columns. Let's see what audit does:
```text
#1/bin/sh
USAGE="$0 audit_file key <[ @ ] column>... "
```
```text
AUDITFILE=$1
shift
```
```text
echo -n ‘date +%ytm#dtH8M%S’ >> $AUDITFILE
echo -n $1 >> $AUDITFILE
shift
```
```text
while [ $# -gt 0 }
do
echo -n " $1" >> S$AUDITFILE
shift
done
echo "" >> $AUDITFILE
```
Another good example of when to use the ‘#' form of shell validation is when you're updating hash keys and decodes created by jvindex. This is another time when you only want to record changes which have been committed, rather than contemplated. The putkey command updates hash keys in Jvindex'ed look-up tables. By executing putkey as key
*— PDF-Seite 77 · Buchseite 67 —*
columns are modified, we are able to maintain a fast and up-to-date index as we edit. In the example above, putkey replaces the original contents of the cust\_id column (\<@cust\_id\>) with the current contents of the cust\_id column (\) in the customer look-up table. The jvindex command which created the customer look-up table is:
jvindex customers -ocustomer cust\_id : company Similarly, the lookup program used to display the cust\_id calls getkey to locate the key column cust\_id in the lookup table customer. Here's what this version of lookup does: #1/bin/sh if [ $#-1t 2] then
```text
exit 0
fi
```
```text
TABLE=$1; KEY="$2"
```
```text
DECODE=‘getkey $TABLE $KEY’
STATUS=$?
```
```text
if [ $STATUS -gt 0 ]
```
```text
then
if [ "$DECODE" != "" ]
then
cursor $ROW $COLEND
echo -n “$DECODE"
fi
exit 0
else
exec 1>&2
echo “$KEY: no such $TABLE"
fi
exit 1
```
The exchange script substitutes the last argument for the first if the first argument is blank, and puts the result in the city column. For example, pressing \ at the city column will cause exchange to insert the words Santa Cruz. This is handy for columns which are often, but not always, a single value. Here's what exchange looks like:
```text
if "$1" = "" ]
```
```text
then
```
```text
echo $2
else
```
```text
echo $1
fi
```
*— PDF-Seite 78 · Buchseite 68 —*
## Control-Key Mapping
Control-key mapping allows you to define a set of ve commands or shell commands to be executed when you strike the specified control key. Control-key definitions are usually tailored to reflect often-repeated command sequences used by particular applications.
Both edit commands and shell commands may be combined for execution by a single control key. For example, let's say you want a command to display a particular file (an image. perhaps) during a ve edit session, and then refresh your screen when you are finished examining it. Your .vere file might look like this:
CTRL-key command
```text
P 1-pic part.snl12 | preview!s
```
In the command above, the first ‘!’ means that a shell command follows; the ‘-’ tells ve to be silent, forcing the suppression of
Hit RETURN to continue
messages and shell newlines that roll your screen up. The remainder of the line, up to a newline or another ‘!’, (whichever comes first) is handed directly to the shell. All information after the ‘!’ are ve edit commands. In this example, ‘S’ will redraw the screen.
The ‘%' symbol in the mapped command means substitute the name of the current database at this position. It works both interactively and in .verc shell commands. Try typing the sequence :!cat % next time you're editing with ve.
You can pass column contents from the record being displayed by ve to the shell via the -verc file. The syntax is similar to that used by the report program: column names enclosed in ‘\<’ and ‘\>’ are replaced by the contents of the column when the command is executed. We can illustrate a simple solution to the “long text field” problem. In this example, ve is used to maintain a table of bug reports:
```text
number date customer staff product
1 891212 cray evan /rdb
2 891107 sun wright ve
2 891107 sun wright ve
```
Because the description of bugs and fixes might be a few paragraphs, we do not want to confine it to a column in a table. How, then, can we tie it to our data base and manipulate it from ve?
We use the contents of the (unique) number column as the name of a text file which contains the bug description. To keep these files in an orderly manner, we will collect them in a separate directory and use the name of the data base to name the directory. To distinguish between the name of the table and the name of the directory of reports, we'll capitalize the first letter of the directory name (Bugs). Because the reports will be openended text files, we will use a text editor to enter and modify their contents.
All of this can be accomplished by mapping a control key to a shell command which edits the desired file name in the appropriate directory:
*— PDF-Seite 79 · Buchseite 69 —*
```text
e tvi ‘echo % | cap’/\n
```
If we are on record number 43 and we hit \, ‘%' will be replaced by bugs; \ will be replaced by 43; the shell will evaluate
```text
‘echo bugs | cap’
to be Bugs. and the resulting path name, Bugs/43 will become an argument to vi.
Finally, use to see the contents of your .verc file from ve.
```
The approach of allowing broad shell access from within ve opens the door to all kinds of powerful and time-saving data base routines that can be designed and implemented by relatively naive users. The following rules should be followed to avoid pitfalls and confusion:
1. Do not put spaces between the enclosing angle brackets and the column name when you are specifying a column name for content substitution. This will cause ve to assume that ‘\<’ is redirect the standard input and ‘\>’ is redirect the standard output, and the column name will be passed to the shell uninterpreted.
2. Use ‘\\’ to send the ‘%' symbol through to the shell without being replaced by the name of the data base.
3. Use ‘-' after the ‘!’ in shell commands to suppress the normal messages and
newlines issued by ve and the shell. This is handy when you don't want to disturb the current screen or window — for example, if you simply want to pop up a subwindow in an unused portion of your screen and you do not wish ve to redraw over it.
4. Use ‘!’ to ensconce shell commands between edit commands.
Command-line Options
ve recognizes the following command-line options:
-d This was implemented to prevent accidental deletion of rows, both by the dd command, and by attempting to write a record in which each column has been deleted.
```text
+
```
A more flexible way to start up ve with a particular command (as opposed to the -m or mode option) is with the ‘+’ command. The remainder of the ‘+’ argument is handed directly to ve’s command parser. Of course, because it is part of a shell command, it must be constructed to escape shell interpretation. An example of this is a command which searches for the word sun in the bugs table and appends the word shine to it:
```text
ve bugs +/sun\\eAshine\\e
```
The \\e at the end of sun ends the search pattern; the \\e at the end of shine exits insert mode. The extra \\’s are swallowed up by the hungry shell.
*— PDF-Seite 80 · Buchseite 70 —*
```text
Screen Size and Column Limits
The column limit of 66 fields has been expanded to 512.
```
ve screens can handle up to 158 columns by 64 rows. The size of the window in which ve is executed determines how ve sets up default screens and uses blank space. To override the absorption by ve of available window space, screen files should be terminated by a final blank row. This row is interpreted by ve as the vertical position, after which the message line is to be displayed.
## User Column in Audit Files
The login name of the user is now recorded in the second column of the audit file. Existing audit files must be modified to reflect the addition of the new column prior to appending rows with the new version of ve.
## Fast-Access Indexing From ve
Hash look-up on columns has been implemented for ve. Key columns are associated with the row number stored in the -i file, effectively linking searches on keys to the G command. The following rules apply for initiating key searches:
1. The key column must be marked with the m command prior to specifying the search pattern.
2. Column contents must contain unique information.
3. The entire column must be entered in order for a key search to be initiated (which makes it a good idea to keep key columns short).
Key columns are created with vindex by preceding the column name with the -k switch. For example, to key the number column of the bugs table and have it decode to the customer column:
```text
vindex bugs -k number : customer
```
Searching for key columns is done in the ordinary way: simply precede the search pattern with ‘/’. If it matches a hash key, the row is retrieved by it's indexed position in the table. Otherwise, row-by-row pattern matching is performed. The method ve uses to find hits is not obvious to the user (except in the case of large tables, where indexed searching is significantly faster) and requires no additional expertise.
## What Is the Cost of Indexed Searching?
When the last user exits an edit session on a table. the squeeze program is executed in the background to clean up the table, putting records back in entry order and removing the holes left by deleted records. This process reconstructs the table-i file. which keeps track of row positions. Because indexed keys also use this information, they too must be updated after the table has been “squeezed.” This process happens automatically when squeeze is finished. The cost is the amount of time it takes to re-vindex each of the key columns for the entire table.
To protect the table during the squeeze and vindex processes, a lock file (table+Ick) is created. When both the squeeze and vindex processes are complete, the table+Ick file disappears. It is important not to tamper with the table until the lock file is gone. Depending on the size of the table and the number of indexed key columns which must be updated, this can take a few minutes. So, the more keys you create, the longer it will take
*— PDF-Seite 81 · Buchseite 71 —*
to put it all back together after everyone has exited. For transaction processing, the best strategy is to keep the table active (at least one ve user) during busy times.
*— PDF-Seite 82 · Buchseite 72 —*
*— PDF-Seite 83 · Buchseite 73 —*
# Section 6 — Data-Base Design
When you try to design your first data base, you are likely to be quite confused. Which data go into which tables? Can you have just one big table? Should you have lots of little tables? How do you find out? It turns out that there is a simple way to decide how to lay out your data base. Once you learn it, any application will be easy. This chapter will show you how.
## One-to-One Relationships in One Table
When you look at your data. you will notice that some information has what we call a oneto-one relationship. For example, each person has a first name, a last name, a birthdate, a sex, an ID number, and so on. All of these items of information can be put into one table. Here is such a table that is called employee:
Id First Last Birth Sex
```text
nt Howard Ho 450503 Male
```
2 Jane Dobbs 540129 Female
The rule then is put all one-to-one relationships into a single table. Another example is department:
Dept Name Head Address
1 act Jones Basement
2 sales White 4th Floor
## One-to-Many Relationships in Two Tables
Another relationship is one-to-many. People have a one-to-many relationship with their children. A person can have from zero to many children. Relational data base theory insists that one-to-many relationships cannot be put into one table, but require two. In addition to the employee table, you will need a child table:
```text
Parent Name
1 Sally
1 Lynn
```
Note that Howard Ho (Id 1) has two children, Sally and Lynn. However, Jane Dobbs (Id 2) has no children, because her Id (Parent) number is not in the child table. To put this information back together, use the Jointable command:
```text
jointable employee child
```
This yields:
*— PDF-Seite 84 · Buchseite 74 —*
```text
Id First Last Birth Sex Name
1 Howard Ho 450503 Male Sally
1 Howard Ho 450503 Male Lynn
```
Here we have the two tables, employee and child, joined together on the employee Id and the child Parent key columns. These connect the two tables for the jointable command.
Note that since Howard Ho has two children, he has two rows in the table. Also note that Sally Dobbs was not included in the table because she has no children.
You can begin to see why we need to keep these kind of data in separate tables. We need information on employees, even when they have no children. Of course, we could include Sally Dobbs and leave her children column empty, but that will complicate processing.
More seriously, we have all of the information on Howard Ho repeated for each child. This not only wastes space, but requires that when we update the table we have to find every entry for Howard Ho and correctly make the update. The extra time and effort, plus the risk of errors, make the single table approach unacceptable. Therefore, we must keep one-tomany relationships in separate tables and join them together only when needed.
## Many-to-many Relationships in Three Tables
There are also several many-to-many relationships. For example, students take zero to many courses and courses have zero to many students. This relationship requires three tables.
First we need a student table:
```text
Student First Last Year
1 Jim Clark 2
2 Mary Witte 1
```
We also need a course table:
```text
Course Credit Room Day Time
art-la 3 RB-8 MWF 10am
chem-1 4 HA-18 TTh 2pm
```
To connect these two tables, a third table is needed that we will call course.student:
```text
Course Student
art-la 1
chem-1 2
chem-1 2
```
We can join these tables together with two jointable commands. First let's use the jointable command to see individual joins:
```text
jointable course course.student
```
This yields:
*— PDF-Seite 85 · Buchseite 75 —*
```text
Course Credit Room Day Time Student
art-la 3 RB-8 MWF 10am a
chem-1 4 HA-18 TTh 2pm 1
chem-1 4 HA-18 TTh 2pm 2
```
Next, the command
jointable -j Student student course.student
yields:
```text
Student First Last Year Course
1 Jim Clark 2 art-la
1 Jim Clark 2 chem-1
2 Mary Witte 1 chem-1
```
All together now:
```text
jointable -j Student student course.student | \
jointable -j Course - course
```
which gives us:
Student First Last Year Course Credit Room Day Time
```text
1 Jim Clark 2 art-la 3 RB-8 MWF 10am
1 Jim Clark 2 chem-1 4 #HA-18 TTh 2pm
2 Mary Witte 1 chem-1 4 HA-18 TTh 2pm
```
So we can bring it all together when we want to see it, but we keep many-to-many relationships in three separate tables.
Planning
When you look at your application, look for the kind of relationships that you have and group your data accordingly. Continuing the college example above, we will also need tables for instructors, rooms, and so on. There is a one-to-many relationship between instructors and classes: instructors often teach several classes, but classes have one instructor (unless there is team teaching).
Note that you have to think of exceptions. If the exceptions are very rare, you might choose to ignore them. But if there are more than a rare instance of classes having more than one instructor, it becomes a many-to-many relationship. Then you will need three tables, because you will need a connector table.
Our college data base will also need a room table. What is the relationship between rooms and courses? Can you see that it is one-to-many? A course is in only one room. (Is it always? What about labs? Or are labs separate courses?) But rooms have more than one course in them at different times, unless we have a terribly inefficient college. So how many tables will we need? One-to-many requires two tables. Which tables do we need? In this case a course table and a room table. The course table will have the room number in it. but the room table will have no mention of the courses in it because there are many.
*— PDF-Seite 86 · Buchseite 76 —*
To find the size of the room for each course, join the room table with the course table:
```text
Course Credit Room Day Time Teacher
art-la 3 RB-8 MWF 10am 3
chem-1 4 HA-18 TTh 2pm 1
cs-101 4 DB-1 MWF 2am 2
econ-1 3 RB-8 TTH ipm 2
his-10 3 HA-18 MWF liam 3
```
And we need a Room table:
Room Type Size Hall
```text
DB-1 Lecture 250 Daddy Bucks
HA-18 Lab 17 Hillary Addler
RB-8 Tacky 23 Roberta Bucks
```
Then, use the commands sorttable and jointable to combine them:
```text
sorttable Room < course |
jointable -j Room - room |
column Course Room Size > room.size
```
This creates the table room.size, as follows:
```text
Course Room Size
cs-101 DB-1 250
chem-1 HA-18 17
his-10 HA-18 17
art-la RB-8 23
econ-1 RB-8 23
```
So, it turns out that designing a data base is easy. Just practice thinking about these principles with different applications.
Normalization
The approach we have just discussed is the easiest way to think about designing your data base. However, most of the data base literature approaches the problem from a different angle. To help you understand that literature, these other approaches are discussed in the following sections. It is more technical and can be skipped on first reading, or if you are just beginning to use data bases. In the technical relational data base literature, this process of correctly grouping data into tables is called normalizing.
## Functional Dependency
Before discussing normalization, several concepts must be understood. Functional dependency refers to whether the data in one column determine the data in another. In other words, if you know the data in one column, can you tell what the data in another column will be? If the data in one column are repeated, are the corresponding data in the other column also repeated? If so, there is a functional dependency, otherwise not.
*— PDF-Seite 87 · Buchseite 77 —*
For example, look at these two tables. First, the room.size table we previously created:
```text
Course Room Size
cs-101 DB-1 250
chem-1 HA-18 17
his-10 HA-18 17
art-la RB-8 23
econ-1 RB-8 23
```
Note that when a value in the Room column is repeated, the corresponding Size value is also repeated. (See RB-8 is in the Room column with the same Size of 23. Also the same for HA-18 and 17). Therefore, Room functionally determines Size or an equivalent way of saying it, Size is functionally determined by Room. Ordinarily, we do not want to have tables with functional dependencies in them, It is acceptable here, because we used a join to put this table together. It is a query of our data base and not a proper table of the data base.
Keys
Key columns are the unique identifiers of each row in the table. The key column or columns of a table should always determine each of the other columns of the table. The function of a key is to uniquely identify the data in the other columns. So the rule is that only key columns can functionally determine other columns. Nonkey columns should not functionally determine other columns in a normalized data base.
## Universal Relation
The opposite of normalization is the universal relation. Imagine one large table that has all of the tables joined together. It has all of the columns of all of the tables across the top. It is the worst case of a unnormalized data base. Why? What is wrong with such a table?
We need to avoid unnormalized tables because they create severe problems for us.
## Redundancy Problems
One problem is that we have a lot of redundant data. Look at the room.size table again and note that the size information for each room is repeated:
```text
Course Room Size
cs-101 DB-1 250
chem-1 HA-18 17
his-10 HA-18 17
art-la RB-8 23
econ-1 RB-8 23
```
This takes up more space than necessary and slows down the programs that must process it.
*— PDF-Seite 88 · Buchseite 78 —*
## Update Problems
Another problem is the extra work and errors that result from trying to update such a table. Suppose we add more chairs to HA-18. We have to update the new Size twice. In this simple table, that is not much work, but in a large data base it is overwhelming. And what happens when we make an error in our updating? It is hard to find and correct. After a while, we will not know which conflicting value is correct. Our data base will become hopelessly corrupted.
## Insert and Delete Problems
There are also insert and delete problems. Suppose we want to add a room and its size to this data base. If it does not yet have a course in it, we can't put it into the table unless we give it a blank course. This creates problems when searching and joining. How do you handle blank or null values?
Likewise with deleting. What if a course is still assigned to the room after the building has been demolished? You don't want to drop the course, but you need to delete the room from the data base.
## First Normal Form
For relational functions to work, tables must be simple or, as it is called in the literature, normalized. There are a number of steps to simplifying, or normalizing, a table. Most importantly, you must never have a variable number of columns in a table. For example, in a file of college employees, you might be tempted to have a column for the first name of the
children of employees:
Emp# Name Dept Child
1 Martin 1204 Sally, Fido
2 Moore 1339
3 Mapes 1045 Jan, Shawn, Peter, Barbara
This creates many problems, not the least of which is that the relational functions will not work. The answer is to have two files, one for employees and another for their children. The child file would look like this:
```text
Peter
3 Barbara
```
When you need to put the two files together. you do so with a join (jointable in /rdb because there is a COHERENT command named join, which works on files without headers). This is another way of saying that one-to-many relations must be represented in two tables. When all of the one-to-many relations are in separate tables, we say that the data base is in first normal form,
*— PDF-Seite 89 · Buchseite 79 —*
## Second Normal Form
Both second and third normal forms require that nonkey functional dependencies be removed by creating additional tables. In the case of second normal form, we look for dependencies on columns within the key. Keys can consist of more than one column. For example, consider a grade table:
Course Student Grade
```text
art-la 1 3
art-la 4 4
chem-1 1 3
chem-1 2 2
chem-1 3 2
cs-101 2 1
cs-101 4 4
econ-1 i 3
econ-1 2 3
econ-1 3 2
his-10 1 3
```
Note that it takes two columns to make a unique key for each row. Both the Course and the Student columns make up the key. Grade is a nonkey column. What we must look for is a dependency between one of the columns in the key and the other columns. In this case there are none, so this table is in second normal form.
But suppose we added a column for class rooms. Since the Room column depends upon the Course column. we would not be in second normal form. This is called a partial dependency because columns are dependent on a partial key. that is. less than all of the columns of the key.
## Third Normal Form
Third normal form requires that we also eliminate any dependencies between nonkey columns. These are called transitive dependencies.
Consider, for example, the room.size table:
```text
Course Room Size
cs-101 DB-1 250
chem-1 HA-18 17
his-10 HA-18 17
art-la RB-8 23
econ-1 RB-8 23
```
Here the Size column depends on the Room column. To reach third normal form we must make two tables: one called course.room, with the Course and Room columns; and the other called room, with the Room and Size columns.
*— PDF-Seite 90 · Buchseite 80 —*
## Normalizing Example
Let's start with a simple universal table and normalize it step by step. Suppose we go to the dean of the college to work out the college data base for grades. Since the dean does not know about normalization, she lists all of the items she wants to keep track of, but our job is to put them into tables. The universal table she builds might look like this:
Course Student Grade Teacher Title Child
```text
chem-1 1 3 4 Assist. Sally, Mike, Joy
chem-1 2 2 1 Assist. Fred
```
chem-1 3 2 1 Assist.
```text
cs-101 2 1 2 Prof. Fred
```
cs-101 4 4 2 Prof.
```text
econ-1 iL 3 2 ~=Prof. Sally, Mike, Joy
econ-1 2 3 2 Prof. Fred
```
econ-1 3 2 2 Prof.
```text
his-10 1 3 3 Assoc. Sally, Mike, Joy
```
Look at this unnormalized table and see if you can normalize it before we show you how.
First normalization requires that we get rid of the one-to-many relationship between students and their children to remove multiple values in the Child column. We create a new table for children of the students:
```text
Student Child
1 Sally
1 Mike
1 Joy
2 Fred
```
We could add more columns about each child to this table as long as we are careful not to include information about the student-parent which should be put into the student table. We also remove the Child column from the big table. The command column accomplishes this task:
```text
column Course Student Grade Teacher Title < universe
This yields:
Course Student Grade Teacher Title
```
```text
chem-1 1 3 1 Assist.
chem-1 2 2 1 Assist.
chem-1 3 2 “ F Assist.
cs-101 2 1 2 Prof,
cs-101 4 4 2 Prof.
econ-1 1 3 2 Prof.
econ-1 2 3 2 Prof.
econ-1 3 2 2 Prof.
his-10 1 3 3 Assoc,
```
For second normal form we have to realize that we have a multi-column key: Course and
*— PDF-Seite 91 · Buchseite 81 —*
Student, which uniquely determines each row. Let's look for dependencies between either of these columns and the other columns. As you can see. Course determines Teacher. So. let's use column to create a new course.teacher table:
column Course Teacher Title \< universe \> course.teacher
This table appears as follows:
```text
Course Teacher Title
chem-1 1 Assist.
chem-1 a Assist.
chem-1 1 Assist.
cs-101 2 Prof.
cs-101 2 Prof.
econ-1 2 Prof.
econ-1 2 Prof.
econ-1 2 Prof.
his-10 3 Assoc,
```
And, then use column to create a table called grade:
column Course Student Grade \< universe \> grade
This yields:
Course
```text
cs-101
cs-101
econ-1
econ-1
econ-1
his-10
```
Student
PWN ENWNHH
WBNwWWERHENNW
Note that there are many redundant rows in the course.teacher table. We can reduce the table to unique rows by using the COHERENT uniq command to remove duplicate rows:
```text
unig < course.teacher
```
This yields:
```text
Course Teacher Title
chem-1 1 Assist.
es-101 2 Prof.
econ-1 2 Prof.
his-10 3 Assoc.
```
The grade table is now in second and third normal form, but the new course.teacher table is only in second normal form. Note that Title depends upon Teacher. We need another table; so we'll use column to create it, as follows:
*— PDF-Seite 92 · Buchseite 82 —*
column Teacher Title \< course.teacher | uniq \> teacher
The new table, called teacher, contains the following:
```text
Teacher Title
5 E Assist
2 Prof.
3 Assoc.
```
```text
Now, we'll use column to check the contents of course.teacher:
column Course Teacher < course.teacher
```
This writes the following onto the screen:
```text
Course Teacher
chem-1 1
cs-101 2
econ-1 2
his-10 3
```
```text
So now the teacher and course.teacher tables are in third normal form. How many tables
do we have? What are their names? What columns are in each table? How would you
explain to the dean what you have done to her nice big table? Why have you done it?
```
## Complex Queries with Joins
When data are distributed to many tables, how can we get the information we want? It is easy to project columns and select rows from a single table and join two tables. But what if the information we want is widely separated?
As an example, let us imagine that you are an instructor in a college and want a phone book of all of your students, just in case you need to call to tell them that the class was canceled or that the final exam date or room had changed. Suppose all you know is your own name and the different tables in the data base:
Table of College Data Base Tables
Table Columns
```text
teacher Teacher First Last Address City State Phone Title
teacher.course Teacher Course
```
```text
course Course Credit Room Day Time Teacher
course.student Course Student
```
```text
student Student First Last Year Phone
```
Such a phone book or listing can be produced with a single pipeline. First let's think through the solution. Then we will build the one-line query.
You know your name, so you can find your ID number in the teacher file. With your teacher ID number, you can get a table of all of your class ID numbers from the teacher.course connector file. Then you can pick up the student ID numbers from the course.student connector file. Finally, you can project the information you want about each of your students.
*— PDF-Seite 93 · Buchseite 83 —*
Pipeline Join Now let's look at the pipeline. It has been written down the page to make it easier to read
and modify. When the Bourne and Korn shells sees the pipe symbol at the end of a line, they know to continue to the next line because this line is not finished:
```text
row ‘First == "Joy" && Last == "Xi" ‘ < teacher |
column Teacher |
```
```text
tee tmpl |
```
```text
jointable - teacher.course |
column Course |
```
```text
sorttable |
```
```text
tee tmp2 |
```
```text
jointable - course.student |
column Student Course |
sorttable |
```
```text
tee tmp3 |
```
```text
jointable - student |
```
```text
column Course Last First Phone |
sorttable > phonebook
```
This probably looks overwhelming, but don’t worry, we are going to go through each part. First, let's look at the output so that we will know where we are going with all of this.
```text
Course Last First Year Phone
cs-101 Dunce Boris 2 765-4321
cs-101 Early Mary 4 123-4567
econ-1 Early Mary 4 123-4567
econ-1 Farkel Freddy 3 123-1234
econ-1 Knott Why 1 123-7654
Note that the command
tee tmp
```
has been inserted in three places in the pipeline. The COHERENT tee command writes the standard input to the standard output, but also write the stream of characters into the file tmp. By looking at the tmp files, we have a peephole into the pipeline so that we can see how the data look at each point. Therefore, we can see and discuss the data at three points in the pipeline.
```text
tmp1
```
Assuming your name is “Joy Xi", you can select the row in the teacher file in which the first name, First, is “Joy” and the last name, Last, is “Xi". Then you can project the Teacher ID number column only. column throws away the other columns. This is to reduce the amount of data flowing through the pipe to speed up the execution. It also avoids conflicts in the names of columns:
*— PDF-Seite 94 · Buchseite 84 —*
```text
row ‘First == "Joy" && Last == "Xi" ’ < teacher |
column Teacher |
tee tmpl1 |
```
Now let's see what the data look like by looking at the tmp] file:
Teacher
2
Here we have gotten the Teacher ID number in a little table that we can now use to find more data.
tmp2 The next four lines join the single-line table above with the teacher.course table to pickup
the courses that “Joy Xi" teaches. Then only the Course column is projected. It must be sorted for the next join:
```text
jointable - teacher.course |
column Course |
```
```text
sorttable |
```
```text
tee tmp2 |
```
By taking a look at our data now, we see that “Joy Xi" teaches two courses:
Course
```text
tmp3
```
Now we can join this two-row table to the course.student table to pick up the students in her classes. This time we project not only their ID numbers but the courses because we want that information carried on to the phone book. The Student column also must be sorted for the next join. We have to tell the sorttable command that the Student column is numeric, instead of string, to get a correct sort:
```text
jointable - course.student |
column Student Course |
sorttable -n |
```
```text
tee tmp3 |
```
Here is the output of these lines:
```text
1 econ-1
2 cs-101
2 econ-1
3 econ-1
4 cs-101
```
Note that we have only the Student and the Course columns, and that the Student column
*— PDF-Seite 95 · Buchseite 85 —*
is correctly sorted.
## Phone Book
The last lines join this table above with the student file to get the student information. Then the columns we want for the phone book are projected. Note that we project the Course column that was carried along as well as columns from the student table. We must sort the new phone book by course so that the teacher can see all of the students in one class:
```text
jointable - student |
column Course Last First Phone |
sorttable > phonebook
```
Let's see the final output phone book again:
Course Last First Year Phone
```text
cs-101 Dunce Boris 2 765-4321
cs-101 Early Mary 4 123-4567
econ-1 Early Mary 4 123-4567
econ-1 Farkel Freddy 3 123-1234
econ-1 Knott Why 1 123-7654
```
Note that we have done this in such a way that some students’ information is repeated if they are taking more than one class from this teacher. Mary Early, in the table above, is an example. We accept this repetition so that the teacher can call all of the students in a particular class. If we had just a list of all the students, we would not know which student was in what class. But you can change this example many different ways by changing the column, sorttable, and jointable commands.
*— PDF-Seite 96 · Buchseite 86 —*
*— PDF-Seite 97 · Buchseite 87 —*
# Section 7 — Shell Programming
The great advantage of the COHERENT system is that most of the work is done for you. Most data base systems create a new language that you must learn, but /rdb uses COHERENT programs and the shell programming language. If you already know these COHERENT tools, there is little more to learn. If you don’t know the COHERENT system, it is much better to learn the general-purpose COHERENT system than a special language that is only good for a single data base package. COHERENT tools as they are delivered on your system can do much of the data base application. /rdb only extends the COHERENT system by adding more than a hundred commands that will make data base handling easier and faster.
## Data-Base Programming in COHERENT Shell Language
It is the shell programming language that make this approach so easy and powerful. The shell is the user interface to the COHERENT system. It prompts you for commands. rewrites your command line to save you typing, and executes the programs you request. It is extremely simple to learn. You start by putting commands that you would type at the terminal, into files called shell programs. These files can be executed simply by typing their names.
But the shell is also a powerful string-oriented programming language with control flow statements like if. for. and while. You can mix procedural with nonprocedural statements.
Procedural programs are the traditional step-by-step instructions that tell the computer how to do something. Nonprocedural statements simply tell the computer what to do. For example, a traditional procedural program will tell the computer how to sort a file. A nonprocedural statement in the COHERENT system would be
```text
sort file
```
where file is the name of the file we want sorted. The COHERENT sort command knows how to sort a file, so we get what we want with out worrying about details. If we had to write the sort program, it would take ten to 100 lines of code, or more. Nonprocedural is much easier and saves a lot of time. It is also much faster to fix. Options to the sort program can reverse the sort. Editing a sort program is much trickier.
Of course. nonprocedural is best. but if a system is all nonprocedural. it has to anticipate everything you will ever want to do! Most fourth-generation systems have this problem: they give you a lot of functions, but lack procedural language statements to let you program what they don't have. Third-generation languages let you program anything. but force you to carefully code too many basic functions over and over. The COHERENT system gives you a nice mix of predeveloped programs that cover all of the basic actions, and the shell programming language to allow you to code more complex functions by building up basic functions.
In the COHERENT environment, you are constantly in a process of automating your work. First, you try out a simple program. Then call it, and other programs, from a higher-level program. Soon you are able to do many things with simple keystrokes.
*— PDF-Seite 98 · Buchseite 88 —*
There are a number of books on shell programming, in addition to the COHERENT documentation. Before we discuss shell programming further. we will need some COHERENT programs to build applications.
## COHERENT Utilities
In addition to the /rdb commands, there are several COHERENT utilities that you will probably need often. Your COHERENT documentation provides detailed descriptions of these commands; we briefly describe some of their data base uses.
```text
awk: Language to Produce Complex Reports
```
awk is the heart of several /rdb commands. awk provides the engine for the row, compute, and validate commands. It can be used by itself to do powerful things to tables. For more advanced applications, you must refer to the awk Lexicon entry and tutorial.
```text
cat: Display a Table or List File
cat is used all the time to list out your tables.
```
```text
echo: Repeat a Statement
```
This command repeats text. It lets you easily pass arguments to command and expand environmental variables.
grep: Find All Rows That Contain a Given String
grep lets you search a table or any text file for a string of characters. If a match is found, the line is printed. It is a primitive search, but easy to use.
od -c: Octal Dump All Bytes as Characters
od lets you see special characters and can be used to see if your tabs are in place. (The /rdb see command is better for this purpose.)
sed: Stream Editor to Edit File in a Pipe
sed is a very powerful program for editing your tables in a pipe stream. Many of the /rdb shell programs use it. You can perform almost any editor command with it.
```text
sh: COHERENT Shell Programming Language
```
sh is the COHERENT shell program that interfaces to the user. It prompts with a dollar sign (8) or other prompt, then reads the commands that the user types. It is a powerful string-oriented programming language. You can create any complex application with it and the COHERENT and /rdb commands.
ksh is the other COHERENT shell programming language. It is, for the most part, a superset of sh. It differs from sh mainly in that it lets you recall, edit, and resubmit command that you had typed earlier, using MicroEMACS-style editing commands. See the COHERENT manual's Lexicon entries on sh and ksh for descriptions of each language, and how they differ.
*— PDF-Seite 99 · Buchseite 89 —*
spell: Check Spelling in a Table or List File
You may find this quite useful for checking spelling in a file. It is also a good example of the power of shell programming.
tail: Display Bottom Rows of a Table or List File tail outputs the end ofa file. You can use it to “behead” a table. Consider table mailtable:
```text
for the same purpose.
Number Name Company Phone
```
```text
1 Ronald McDonald McDonald‘s (111) 222-3333
2 Chiquita Banana United Brands 1234
```
The command
```text
tail +3 mailtable
```
yields:
```text
1 Ronald McDonald McDonald’s (111) 222-3333
2 Chiquita Banana United Brands 1234
```
As you can see, the first two “head” lines of the table have been thrown away. There is also the /rdb command headoff
```text
we: Word Count
```
This command counts the characters, words, and lines in a file.
## Text Editor to Enter and Update Files
A text editor is important to your work, because you will use it to set up tables and lists and to write your shell program applications. COHERENT comes with three interactive text editors:
ed This is a powerful, line-oriented editor. This editor is best for making mass transformations of a file, because you can use normal expressions to tell it what to do. ed is also useful in editing files that are too large for a screen-oriented editor to handle, at least in the 80286 edition of COHERENT.
me This is the MicroEMACS editor. It is the preferred editor of most COHERENT users. As its name implies, it is a smaller, more efficient version of Richard Stallman’s famous EMACS editor. With it, you can display multiple files in multiple windows upon your screen, move text from one file or window to another. Unlike ed, MicroEMACS lets you address the text to be edited by moving the cursor to it — hence, it is considered to be a “screen-oriented” editor.
vi This is the COHERENT implementation of the UNIX standard editor. It has features of both ed and MicroEMACS, plus many features of its own.
Each editor is summarized at length in the COHERENT Lexicon. The COHERENT manual also contains tutorials for ed and me. Any of these three editors will do the job for you; which you select is largely up to your personal preference. Each editor has its strengths and weaknesses; an editing job that takes hours with one editor might take only minutes
*— PDF-Seite 100 · Buchseite 90 —*
with another. You would do well to learn at least the riduments of each editor, so you can select the right editor for a given editing job.
## Reading and Writing Data Base Files
When you write programs, you have to open files. In the COHERENT environment, files usually come to the program from standard-in and output is sent to standard-out. But sometimes you have a shell program that is talking to the user at the terminal through the standard-in and -out, but has to open one or more files for reading and writing. This is done with the exec command. This code opens /filein for input (read) and assigns the file descriptor 3, fileout is opened for output (write) and assigned file descriptor 4. Then programs can use those file descriptors with the \<&3 and \>&4 conventions:
```text
exec 3< filein
exec 4> fileout
cat <&3 >&4
```
The COHERENT shell's read command cannot have its input redirected to a file other than standard-in, except by a trick:
```text
exec 0< inventory
read HEAD
```
```text
Here, we have set the environmental variable HEAD to contain:
Item Amount Cost Value Description
```
In a loop you can read a whole file line by line. The while statement is a control statement that executes the lines within the do and done until read tries to read the end-of-file and returns a status code indicating false.
```text
exec 0< inventory
while read HEAD
do
```
```text
echo “$HEAD"
done
```
```text
This yields:
Item Amount Cost Value Description
```
```text
4 3 50 150 rubber gloves
2 100 5 500 test tubes
```
3 5 80 400 clamps
4 23 19 437 plates
```text
5 99 24 2376 cleaning cloth
6 89 147 13083 bunsen burners
7 5 175 875 scales
```
*— PDF-Seite 101 · Buchseite 91 —*
## Parsing Rows
You can use the set command to parse strings in the shell. For example, if you want to get at any field in a row you can read the row into a shell variable and set the words in the row to the shell positional arguments $1 and $2:
```text
exec 0< inventory
```
```text
read HEAD
```
```text
set $HEAD
```
echo “The first field is $1 and the fifth field is $5."
The final command, echo, displays its first and fifth arguments. This prints the following:
The first field is Item and the fifth field is Description.
## Tables to Shell Variables
It would be very nice if we could use the column names from a table to refer to the column values in a shell program. Often people assume they have to walk through the row with for and, perhaps, shift commands. This slow method is not necessary. Here is a neat trick for using column heads as variables in shell programs.
Consider, to begin, table inventory:
Item
NOUPWNHHE
Amount Cost Value Description
```text
3 50 150 rubber gloves
100 5 500 test tubes
§ 80 400 clamps
23 19 437 plates
99 24 2376 cleaning cloth
89 147 13083 bunsen burners
5 175 875 scales
```
Now consider the shell script onhand:
```text
USAGE=’usage: onhand Item < inventory’
```
```text
FOUND=0
NOFOUND=1
read HEAD
read DASH
while read $HEAD
do
if test "$Item" -eq "$1"
then
echo We have $Amount $Description on hand.
exit $FOUND
i 9
```
```text
done
exit $NOFOUND
```
Now, the command
*— PDF-Seite 102 · Buchseite 92 —*
```text
onhand 2 < inventory
yields:
```
```text
We have 100 test tubes on hand.
Now, let's walk through onhand and see just what it does.
The first three lines
```
```text
USAGE=’usage: onhand Item < inventory’
FOUND=0
NOFOUND=1
```
set some environmental variables that are used for printing an error message should a mistake occur,
Next, the line
```text
read HEAD
reads the first line of inventory into a shell variable called HEAD.
The next line
```
```text
read DASH
```
reads the dash line into an environmental variable called DASH. We want to throw away the dash line, and this is an easy way to do it.
```text
Next comes the while loop:
while read $HEAD
```
```text
do
if test "$Item" -eq "$1"
then
echo We have $Amount $Description on hand.
exit $FOUND
fi
done
```
Look carefully at the read statement. It examines HEAD, which the shell expands into the list of column names, before read is called. So read really sees all of the column names as arguments:
```text
read Item Amount Cost Value Description
```
read assigns the first word it reads from standard-in to Item, then the next to Amount, and soon. Therefore, it has automatically assigned the column values to the column names for us and we can use them in the shell program with 8 in front.
The test and echo commands both use the variables that hold the values from the current row. Let's see this with the shell execution trace option -x turned on:
*— PDF-Seite 103 · Buchseite 93 —*
```text
+ read HEAD
```
```text
+ read DASH
```
```text
+ read Item Amount Cost Value Description
+ test 1 -eq 2
```
```text
+ read Item Amount Cost Value Description
+ test 2 -eq 2
```
+ echo We have 100 test tubes on hand.
We have 100 test tubes on hand.
This lets you see how the column names and values are rewritten as each row is read, tested, and processed.
## Lists to Shell Variables
Here is an example of how to get records from a list formatted file and make each column name-value pair a shell variable=value pair. It uses the /rdb program listtosh to convert the list record to shell format. Consider the list maillist:
Number 1
```text
Name Ronald McDonald
Company McDonald's
Street 123 Mac Attack
city Menphis
```
State TENN
ZIP 30000
Phone (111) 222-3333
The command
```text
listtosh < mail.list
```
yields:
```text
Number='1’
```
```text
Name=’Ronald McDonald’
Company=’McDonald\'s’
Street='123 Mac Attack’
City='’Menphis’
State=’TENN’
ZIP=’30000’
Phone=’(111) 222-3333’
```
See the tabs converted to equal signs ‘=" and the data protected absolutely by apostrophes (). Also note that each apostrophe within the data is protected with a backslash ‘\\'. This is the format for the shell variable=value assignments. This program can be executed in a shell program and the variable=value pair will become known to the program. The command:
```text
column Name Phone < mail.list | listtosh
yields:
Name=’Ronald McDonald’ Phone=’(111) 222-3333’
```
This one line output from the command substitution is exactly the format the shell uses to assign values to its variables. As you can see, the shell can read multiple assignments on
*— PDF-Seite 104 · Buchseite 94 —*
one line. The apostrophes allow anything to be in the data without being expanded by the shell. In this example, we projected only Name and Phone, to keep from having a long line and to show that we can use any command to get the variables we want.
```text
In the next example, eval is used to rescan and assign the line:
eval ‘column Name Phone < mail.list | listtosh’
echo “$Name’s phone number is $Phone."
```
This yields:
Ronald McDonald’s phone number is (111) 222-3333.
Now we can use the values of the variable in a shell program. This example contains an echo statement to see that the variable had been correctly assigned to the current shell. and not to some subshell.
The next example is more complex. A table is searched for a record and converted to list and then used in the shell program:
```text
echo ‘row ‘Item == 3' < inventory | tabletolist | listtosh’
eval ‘row ‘Item == 3’ < inventory | tabletolist | listtosh’
echo "We have $Amount $Description."
```
This yields:
```text
Item=’3' Amount=’5' Cost=’80' Value='400' Description=’clamps’
We have 5 clamps.
```
## Report Writing
UNIX World magazine printed two articles by Alan Winston about fourth-generation programming languages (July 1986 and April 1987). Several competing companies were invited to produce a sample report using their 4GL systems. Most of these languages looked more like COBOL or RPG. Here are two ways of producing the sample report with the COHERENT shell and /rdb.
The first example is a simple default report (which we think looks better than the report format required in the article):
```text
number fname lname code hours rate total
1 John Wilson 2 3 75
7 John Wilson 2 4 75
1 yf
2 Fred Jackson 1 4 85 340
2 Fred Jackson 2 5 85 425
2 9 765
```
*— PDF-Seite 105 · Buchseite 95 —*
```text
3 Anne Rowan 2 5 75 375
3 Anne Rowan 1 6 75 450
3 11 825
```
2115
Following is the shell script that produces this default report. Note that it only takes only 11 lines of simple, readable code. Actually, it could be written in two lines, but we put each command on a separate line. This example does not require counting columns or characters. There is no “line-at-a-time” processing, as with the other so-called 4GLs — rather, whole files are processed at once:
```text
jointable hours employee |
sorttable code |
jointable -j1 code ~j2 number - task |
sorttable number |
column number fname lname code hours rate total |
compute ‘total = hours * rate’ |
justify > tmp
```
```text
subtotal -l1 number hours total < tmp
```
```text
total total < tmp |
justify |
tail -1
```
The data used in the UNIX World samples were not included in the articles, primarily because their format is virtually unprintable. /rdb data are flat ASCII files. Table hours is as follows:
```text
number hours code
```
```text
ane ew
NNENN
```
```text
a
»
```
```text
number fname lname rate
1 John Wilson 75
2 Fred Jackson 85
3 Anne Rowan 75
```
And table task is as follows:
```text
number name
```
```text
1 unix/world
2 \rdb
```
*— PDF-Seite 106 · Buchseite 96 —*
Here is the exact report format required in the UNIXWorld articles of July 1986:
```text
number Employee Name code hours rate total
1 John Wilson 2 3.00 75.00 225.00
a 2 4.00 75.00 300.00
* Employee Total 7.00 525.00
```
```text
2 Fred Jackson 1 4.00 85.00 340.00
2 2 5.00 85.00 425.00
* Employee Total 9.00 765.00
```
```text
3 Anne Rowan 2 5.00 75.00 375.00
3 4 6.00 75.00 450.00
* Employee Total 11.00 825.00
```
\*\* Report Total 2115.00
And here is the COHERENT shell and /rdb program that produces the exact format:
```text
jointable hours employee |
```
```text
sorttable code |
```
```text
jointable -j1 code -j2 number - task |
```
```text
sorttable number |
```
column number hours code fname lname rate name total |
```text
compute ‘total = hours * rate; name = sprintf("%s %s",fname,lname)’ |
column number name code hours rate total > tmp
```
compute ‘if (name == prev) name = ""; prev = name;\\
```text
hours = sprintf("%4.2f",hours); rate = sprintf("%6.2f",rate);\
total = sprintf("%7.2f",total)’ < tmp |
```
```text
subtotal -l number hours total |
```
```text
compute ‘if (code ~ / / && code !~ /-/) code = "* Employee Total";\
if (code ~ / / && code !~ /~/) number = ""’ > tmpl
```
```text
rename name "Employee Name" < tmp1 |
```
```text
justify -r number hours rate total -l "Employee Name" -c code |
sed "/---/d" | sed "s/*/ /" | sed "s/rate/ rate/" |
```
```text
sed "s/total / total/"
```
```text
TOTAL=‘column total < tmp |\
```
```text
total | compute ‘total = sprintf("%10.2f",total)’| headoff’
echo " \
```
```text
** Report Total $TOTAL"
```
This is still only 22 lines. The powers of the COHERENT shell, awk, and sed programs are used for string and arithmetic processing. The user only needs to know COHERENT tools, not yet another language. If you know COHERENT tools, you understand this; and if you do not, learning them has much greater value than learning yet another special programming language from a single vendor. As COHERENT and MS-DOS/UNIX systems become the standard, you can use your COHERENT skills on almost all computers.
*— PDF-Seite 107 · Buchseite 97 —*
# Section 8 — Shell Menus
When setting up software applications, it can be important to provide menus to the user. These tell the users what options are available. and make it easy for them to choose the ones they want. As more functions are added to the system, they can also be added to the menus. In this chapter a simple shell program menu is discussed.
## Example Shell Menu Program
A simple way to create menus in COHERENT is with a shell script. The advantage of using shell programming is that it is so easy and you can do anything with it. A sample menu program is included with /rdb. You can copy it into your own directory and edit it to be one or more menus for your system, For details see the menu manual page.
The menu program is in two parts. The first half of the menu simply paints the menu selections on the CRT terminal. It is a simple COHERENT cat or echo command:
```text
cat <
*— PDF-Seite 108 · Buchseite 98 —*
```text
case Actions
```
Whatever the user types is assigned to the shell variable ANSWER. (After the first word of the reply, any more words are assigned to the shell variable COMMENT).
```text
read ANSWER COMMENT
case $ANSWER in
```
```text
O|exit) exit 0 ;;
1|Menu) Menu ;;
2|sh) sh ;;
```
```text
3|vi)
```
```text
echo ‘Which file or files do you wish to edit’
read ANSWER COMMENT
vi $ANSWER $COMMENT
4|mail) mail ;;
5| send)
echo ‘Please enter login name of person to send mail to’
read ANSWER COMMENT
echo ‘Type you letter, and end by typing Ctrl-d’
mail $ANSWER
6|cal) (cd ;
7|who) who ;;
8|ls) ls 3;
9|cat)
echo ‘Please enter the name of the file you wish to see’
read ANSWER COMMENT
```
```text
calendar) ;;
```
```text
cat $ANSWER
ae
10|rdb) menu.rdb ;;
*) echo ‘Sorry, but that number or name is not recognized.’ ;;
```
```text
esac
```
After the user's answer is read in, the shell case statement is used to match the answer to a number of possible cases. If the user types a number 8 or Is, then the Is command is executed. This sample gives the user the choice of two ways to indicate a menu selection: numbers or short mnemonic string names.
After the case pattern, you can type any shell command or call any shell program, or any combination of both. This gives you complete power to do anything, as a result of a user's choice. In the previous examples, you can see how to simply execute a command, invoke another menu, ask for more information and use it in a command, and so on. The \*) case is selected if the user does not type any of the patterns previously listed. This gives an error message.
To make this system work. two commands are needed. A clear command clears the screen so that the form can be written on it and the cursor command moves the cursor to each field of the screen.
*— PDF-Seite 109 · Buchseite 99 —*
```text
termput and tput Commands
```
There are many CRT terminals with different capabilities and commands. Terminal capabilities are described in the termcap file, which contain capability descriptions for a number of commonly used terminals. You only need to find out what it calls your terminal and assign that name to the sheli variable TERM. (Be sure to also export TERM). To pick up the command string for a terminal capability /rdb provides the termput command. It searches for the terminal name you assigned to TERM and then for the capability you indicate.
```text
clear Command
```
The clear command clears the screen. To speed up clearing the screen, assign the clear command sequence to the shell variable CLEAR. Then you can use SCLEAR in echo and cat \<\
*— PDF-Seite 110 · Buchseite 100 —*
*— PDF-Seite 111 · Buchseite 101 —*
# Section 9 — Tables and Forms
Simple forms can be used to for data entry and to display data on CRT screens. The two can be mixed with a form in which some fields are filled in and the data from the data base is written into the remaining form fields. /rdb comes with several forms systems: ve, described earlier, and a shell level forms system, described here. ve was designed to make creating and entering data into /rdb data bases easy, using a vi-style interface. The screen program, on the other hand, can be a more general-purpose application development tool that can be customized for any specific application. It's an example of a program generating a program.
To make the shell-level system work, you need the clear and cursor commands, described in the previous chapter.
## Building a Screen Form
You can write a shell script that paints a screen and accepts input. You can clear the screen and use the cursor command to move to any location. There you can use the echo or cat command to display whatever you wish. You can use the read command to read in anything the user types and assign it to a shell variable. You can take the users information and look up data in the data base, using the database query commands, and display it anywhere on the screen. The update,inv command found in the SRDB/lib directory is an example of this.
The screen program uses a screen definition form, which you create with any text editor (just like the /rdb report program form):
```text
Makeapile, Inc. Inventory Update
Item Number:
-
```
Item Cost Value Description
```text
-
```
```text
Amount Onhand:
```
```text
Then you input that form into the screen program:
screen < inv.f > inv.s
```
This yields:
*— PDF-Seite 112 · Buchseite 102 —*
```text
: paint crt screen
exec 3>&1 1>&2
cat <&3
echo “Item Item Cost Value Description Amount"
echo "---- ---- ewe eee ewww ee eeeee ++ -
```
```text
t append row
echo “$Item $Item $Cost $Value $Description $Amount"
```
The output is a shell program that will paint the screen, read the user's input, and output a table of the user's responses. This shell program is simple, but you can edit it to do any advanced operation you like.
*— PDF-Seite 113 · Buchseite 103 —*
# Section 10 — Fast-Access Methods
Fast-access methods allow you to get rows from a table or list file faster than sequentially reading the file. This is very important for larger data bases. Where sequentially reading a huge file would take minutes, the right fast-access method might take only a few seconds to find the records you want. Traditionally, these methods were very important to data-base management systems. For very large data bases, they will continue to be important. But one or a few users on a microprocessor with small to medium-sized tables will seldom need
```text
these speedups.
Appropriate Use
```
It is important to point out that these methods are not always faster and usually require significant time to set up. They are almost never justified unless the file is large (more than 1,000 rows), and the extra time to index or sort the table is worthwhile.
The command row finds rows that match complex logical conditions and regular expression (string patterns). But these fast-access methods require that the key value be expressed more specifically. No greater than, less than, or string pattern matches: only equals, and partial initial matches (for example, the first few letters of a key).
We've implemented five fast-access methods: sequential, record, inverted. binary, and hash. /rdb has two commands that use these methods: index and search.
The index and search Commands
We will use a two-row table to show the index and search commands. Here is a mailtable:
Number Name Company Phone
```text
a Ronald McDonald McDonald’s (111) 222-3333
2 Chiquita Banana United Brands 1234
```
```text
The hash method is often the fastest, so let's use it as an example.
index -mh mailtable Name
```
The -m means method, and the h specifies hash. The index command builds a hash secondary index table. You can see it, if you are curious, by listing out the table name followed by the -h secondary index extension; for example, mailtable.h:
Offset
```text
104
0
```
Each of the names in the Names column of the mailtable was hashed into row 4 (104) or 2 (156). The offset in the hash table (the nonzero numbers) is the location (in bytes) in the
*— PDF-Seite 114 · Buchseite 104 —*
main file, of the row with that key value.
Searching
The search command allows you to search for one or more rows in the table in four different ways. You can input a key two ways, and you can input a table of keys two ways.
Interactive
```text
Now you can search the mailtable by name in an interactive way:
search -mh mailtable Name
```
The search command first prints out the table head line
Number Name Company Phone
```text
then waits for you to type in a key value. In this case, if you type
Ronald McDonald
search prints the following from maillist:
4, Ronald McDonald McDonald’s (111) 222-3333
```
After you type the name and hit the return key. the row will print almost immediately, even if the file is huge. You may continue to type keys. When you are finished, type \.
## Pipe Key
The search command can also be used in a pipe. You can input a table or list of keys through a pipe and the search command will output a table or list of rows which match your input keys. This becomes a fast join. with keys coming in and a table of rows coming out. For example, the command
echo "Ronald McDonald"| search -mh mailtable Name
```text
yields
Number Name Company Phone
```
```text
1 Ronald McDonald McDonald’s (111) 222-3333
File Input
```
In addition to sending a single key to search, you can also send a whole table of keys. search will look up each key and output a whole table of matching rows. It is like a high speed join; keys in, records out.
Here we have our name keys in a table called name:
Name
```text
Ronald McDonald
Chiquita Banana
```
The following command directs it to the standard input of the search command and gets
*— PDF-Seite 115 · Buchseite 105 —*
the matching records out.
```text
search -mh mailtable < name
```
```text
This yields:
Number Name Company Phone
£ Ronald McDonald McDonald's (111) 222-3333
```
2 Chiquita Banana United Brands 1234
Note that you do not have to tell the search command the name of the column to search on, if you send it a table with the column name, because search can pick up the column name from that input table.
## File Input by Pipe
You can also put the search program in a pipeline and it will send to its right a table of rows that match the table of keys coming from its left. In other words, keys in. matching records out.
As an example, consider again the table name:
```text
Ronald McDonald
Chiquita Banana
```
```text
The command
cat name | search -mh mailtable
writes the following to the standard output:
```
Number Name Company Phone
```text
1 Ronald McDonald McDonald’s (111) 222-3333
2 Chiquita Banana United Brands 1234
```
The cat command simulates any program or pipeline that produces a table of keys. including other search commands. Multi-Rows, Multi-Columns, and Multi-Keys
The search command will produce multiple rows, if more than one row matches the key. You can have multi-column keys consisting of more than one column. You can also send more than one key, multi-keys, to search and it will output all matching rows.
## Methods of Searching
The five different fast access methods each have their own advantages and disadvantages. It is an art and a science to figure out which to use in a given situation, or whether to use them at all.
*— PDF-Seite 116 · Buchseite 106 —*
Sequential
Sequential is the simplest and slowest method. It is hardly a fast access method at all. but is included for completeness. This method simply looks at every record in the table for a match. With a big file, this will take a long time.
When might you use it? It is better than grep because a sequential search will look at only a single column for a match, instead of the whole row. Thus it avoids matching strings in the wrong columns of the row.
Also, use the sequential method to time how fast it takes. You will often be surprised that this method is fast enough for your system. If it is fast enough, use it since it requires no indexing or overhead to use. The table can be in any order and can be updated randomly.
Record
One problem with variable-length records is that there is no simple computation of where a row such as number 7 is. Without this method, we would have to sequentially search the table, counting records, until we came to the one we wanted. On the average we would have to search half the file. When we index with this method, the index program runs through the whole file and builds a secondary file which contains the offsets to each row. The secondary index table is named by adding a .r to the end of the table name. It contains fixed length rows so that the record number can be computed. At that address is the offset of the corresponding record in the data-base table. For example, consider the following
```text
mailtable:
Number Name Company Phone
1 Ronald McDonald McDonald’s (111) 222-3333
```
```text
2 Chiquita Banana United Brands 1234
The command
index -mr mailtable
produces index table mailtable.r, which appears as follows:
Offset
```
Note that edch of the offsets in the secondary index table mailtable.r is the byte address of that row in the main mailtable table.
Binary
The binary method requires that the table be sorted on the key columns. With this method. the index command simply sorts the table. The search command can find the desired row by first looking at a row in the middle of the table. It can use the COHERENT system call seek() for fast access to any byte in the file. search compares the key value of that center row with the key it is looking for. If the row’s key is too high, it jumps to the one-quarter point in the file, if too low, to the three-quarter point in the file. Each probe cuts the file in half so that the record can be found quickly.
*— PDF-Seite 117 · Buchseite 107 —*
If there are a thousand records in the table, only ten probes are needed to find the record you wish. One million records require only 20 probes. A billion records need only 30. This is called log n search time, where n is the number of records in the file and the log to the base of 2 is the number of probes needed to find a record. The sorting takes n log n time with the fastest sort routines.
```text
To prepare mailtable for this type of search, use the command:
index -mb mailtable Name
mailtable now looks like:
```
```text
Number Name Company Phone
2 Chiquita Banana United Brands 1234
A. Ronald McDonald McDonald’s (111) 222-3333
```
Note that the Name column is now sorted so that the binary search will work. This is a good method when you have to keep the file in sorted order anyway. Then your sorting pays off twice. It is a painful method, however, if you are adding and deleting records often and have to resort often.
Hash
The hash method takes the key and performs a mathematical operation on it that converts it into a single number. Each ASCII character in the key is added together and modulo-ed with the size of the hash table to produce a number that is its location in the hash table. That number is an index into a secondary hash table. At that location should be the offset to the record in the main table. The row at that offset in the main table is checked to see if its key column(s) match the key we are looking for. If it is, we have found our record.
It might not match because more than one key may hash to the same number by accident. If it does not match, the next offset in the hash table is selected and tested. Each offset is tested until a match is found, or until a value of zero is found. This indicates that there is no matching record in the data-base table. So the search fails. No error message is produced, just no record is output.
As an example, consider again our mailtable:
Number Name Company Phone
```text
1 Ronald McDonald McDonald’s (111) 222-3333
2 Chiquita Banana United Brands 1234
```
```text
To prepare mailtable for a hash-table search, use the command:
index -mh mailtable Name
```
This hashes the contents of the Name column, and writes the results into file mailtable.h:
*— PDF-Seite 118 · Buchseite 108 —*
For example The 104 in the fourth row of the hash table mailtable.h is the byte offset of the first record in the data base mailtable table. The value ‘4’ (for fourth row) is the result of adding the ASCII values of Ronald McDonald together and modulo with 5, the number of rows in the hash table. The size of the hash table is two times the number of rows in the table to be indexed, plus one. Having twice as many hash rows makes it likely that there will be lots of zeros to stop the search for keys. If the hash table is twice as big as the number of keys to hash, then only two probes are needed on average.
Thus, when the search command is searching a table via a hash-key index, it does the following:
```text
° Read the field on which the key has been built.
° Sum the key’s ASCII values.
```
- Modulo the sum by the number keys in the hash table (that is, the number of rows in the data table, times two, plus one. This yields the number of the row to read in the hash table.
- Read the appropriate row in the hash table to find the offset of the row in the data table that we want.
- Use that offset to read the row out of the data table.
Hash is usually the fastest method. But it is best for a static file that you are not updating and do not need to keep sorted.
## Inverted or Indexed Sequential
The inverted method projects the key columns and the offset of each row and sorts on the key columns to create a secondary index file. Then the search command can use a binary search on the key columns to find the right offset into the data-base table.
Consider once again our mailtable:
Number Name Company
```text
1 Ronald McDonald McDonald’s (111) 222-3333
2 Chiquita Banana United Brands 1234
```
```text
To prepare an inverted index for on its column Name, type:
index -mi mailtable Name
This yields table mailtable.i, which appears as follows:
```
Offset Name
```text
156 Chiquita Banana
104 Ronald McDonald
```
Note that the Name column has been projected and sorted and that the offset column contains the corresponding offset in the main table.
*— PDF-Seite 119 · Buchseite 109 —*
## Partial Inital Match
The -x option specifies that partial initial match is to be used. This means you can use only the first few letters of a key, and a match will be made on all those records whose key is matched up to that point. When you type:
```text
search -mi -x mailtable Name
```
search prints the head line and dash line, then wait for you type the key for which to search. If you type:
```text
Ron
then search prints:
1 Ronald McDonald McDonald’s (111) 222-3333
As you can see, Ron matched the first few characters in “Ronald McDonald”.
```
This method of searching helps save you unnecessary keystrokes; but on large tables it will retrieve more rows than you really want.
B-tree
B-tree subroutines are now a standard on computer systems, for those who want to return to software prisons; but of course the easiest to use and most general tree routines are to be found, as usual, in the power of COHERENT itself. What is the hierarchical directory structure but a collection of shell level programs to manipulate a tree? You can use the directory structure itself to implement the first few levels of (tree structured) indices.
For example. in a company data base, you can have a directory for each city; within each city directory, a directory for each department; within each department directory, a file for each employee, each such file having header records and one employee record. Then, to retrieve all the New York sales employees whose names begin with J, one could say:
```text
union nyork/sales/J*
and, to retrieve all sales employees:
union */sales/*
```
COHERENT itself has many programs to manipulate trees. So there was no point in duplicating the power of COHERENT.
The tree method is occasionally appropriate, but usually the most expensive in space requirements. Its advantages are in rapid updates, deletes, and inserts of new records in very large data bases. If you have a very large data base that requires lots of updates, it's really quite fast to build the first few levels of indexing into the COHERENT directory structure, but it does involve extra file system overhead.
Analysis
It takes analysis and testing to determine which is the best method for a given situation. Each method has its advantages and disadvantages. Theory only takes one so far. You can time the different methods on your computer to determine the fastest.
*— PDF-Seite 120 · Buchseite 110 —*
To determine the best method to use in a situation, you must both analyze and test your different options. The advantages and disadvantages of each method is discussed earlier. You should also test any strategy you adopt. You might find that a simpler method is fast enough, or the overhead of a fast method outweighs the benefits of speed.
Management
Fast-access methods need to be managed. If the files are being updated, they may have to be reindexed. Reindexing takes time. You may want to schedule it when users are not accessing the data and perhaps when the computer is not being used much. A nightly reindexing may be appropriate.
The COHERENT command at lets you schedule big jobs like this, at say 3 A.M.. when the system is more likely to be quiet. When you choose an access method, you must plan for any management that is needed. This can also be accomplished by writing a command into the system file /etc/crontab.
*— PDF-Seite 121 · Buchseite 111 —*
# Section 11 — Miscellaneous Commands
/rdb has more than 100 programs to help you develop software applications. Here is a brief discussion of some of them, grouped together by subject.
## Record Locking: One at a Time
When your application requires that several people update the same file at the same time. you must lock records. When one user gets a record to change, it is important that no other user pull out the same record and edit it also. If you allow this, the second record written back will clobber the first record, thus destroying the results of the first user's changes.
Many complain that the COHERENT system does not have a record-locking system. But it is trivial to create record locking with COHERENT tools. /rdb provides lock and unlock commands that you can use or modify for this purpose.
Finding What to Lock To lock a record, /rdb must first find its location within the table where it “lives”.
To find the location of a record, use the seek command. It uses the fast-access method of your choice to find the record and returns the starting and ending byte location, which can be assigned to a shell variable.
```text
For example, consider the command:
LOCATION=‘echo 5 | seek -mb -o tmp inventory Item’
A lot is going on here so let's take it step by step.
```
The echo command sent the number ‘5’ to the seek command. seek looks for an Item numbered 5 in the inventory file using the binary fast access method (-mb), and writes the record into the tmp file (-o tmp). seek sends a string of four numbers to standard out which is assigned to the shell variable LOCATION. Echoing LOCATION gives us a resulting of the form:
207 24509
The four numbers are the offsets of the first byte and last byte of the record in the data file. and of the first byte and last byte of the offset in the secondary index file. (In this case it is meaningless, because the binary method does not use a secondary file.)
```text
lock and unlock
```
Now that we know where a record is, we can use the command lock to lock it while we work with it, and the command unlock to unlock it once we're done with it.
The lock command writes the string from the LOCATION shell variable into a file in the /tmp directory. It checks to see if that area of the file has been previously locked. The unlock command removes the location line from the lock file.
*— PDF-Seite 122 · Buchseite 112 —*
## Blanking a Record
For added protection, or as an alternative, you can also blank out the record in the file. Use seek to get the location, use blank to blank the record, and use replace to write the blank record into the file,
For example, the following command blanks out line 5 in table inventory:
```text
LOCATION=‘echo 5 | seek -mb -o tmp inventory Item’
blank < tmp | replace -mb inventory $LOCATION
```
```text
When we look at inventory, it now appears as follows:
Item Amount Cost Value Description
```
```text
1 3 50 150 rubber gloves
2 100 5 500 test tubes
```
3 5 80 400 clamps
4 23 19 437 plates
```text
6 89 147 13083 bunsen burners
7 5 175 875 scales
```
Line 5 has been replaced by a row of blanks. Since the data are no longer there, no other user can grab them for manipulation. Users must be instructed. however, that a blank row means that the record has been locked. If they retrieve a blank record, they must not replace it with anything.
## Dates: Conversion and Arithmetic
One of the basic tasks a data-base system must perform is manipulating dates. Each date must be translated into a standard format, and users must be given a way to perform arithmetic on dates. /rdb includes several programs help you handle dates.
## Julian and Gregorian
Gregorian is the kind of dates we are all familiar with: January 1, 1989, 1/1/89, 890101, and so on. Unfortunately, there are two problems with this kind of date: Gregorian dates can not be added or subtracted, and they have several different formats. Fortunately, there is another form of date, called Julian, that solves these problems. A Julian date is a number of days since January 1, 4713 B.C., the date that marked the beginning of the Julian calendar. Because a Julian date is an integer. you can add days to and subtract days from a Julian date and get the correct new date.
/rdb has two commands that are used for this purpose. julian converts a date from the standard Gregorian to Julian. It converts a whole column of dates so that they can be operated upon. After the Julian dates have been manipulated, the column can be converted back to Gregorian dates with the gregorian command.
For example, suppose you are planning a project. and have written a schedule into table project, which appears as follows:
*— PDF-Seite 123 · Buchseite 113 —*
```text
Date Description
890601 Start project
890701 Project crises
890801 Abandon project
890901 Coverup blame
891001 Write off losses
```
Now you find that you need to put off the start date of the project by 45 days. To update your table to reflect this change, do the following:
- First, use the command julian to convert the Date column to Julian dates: julian Date \< project \> tmp The output has been written into table tmp, which appears as follows: Date Description
```text
1752623 Start project
1752653 Project crises
1752684 Abandon project
1752715 Coverup blame
1752745 Write off losses
```
```text
Those huge numbers under Date are Julian days.
° We can now add 45 days to the column with the compute command:
compute ‘Date += 45’ < tmp > tmpl
The result is written into table tmp1, which appears as follows:
```
Date Description
```text
1752668 Start project
1752698 Project crises
1752729 Abandon project
1752760 Coverup blame
1752790 Write off losses
```
```text
Note that all of the Julian dates are 45 days later.
° Now we can convert back to Gregorian:
gregorian Date < tmpl > project
```
The result is written back into our original table, project, which now appears as follows:
*— PDF-Seite 124 · Buchseite 114 —*
```text
Date Description
890716 Start project
890815 Project crises
890915 Abandon project
891016 Coverup blame
891115 Write off losses
```
This can also be done in one pipeline:
```text
julian Date < project |
```
```text
> compute ‘Date = Date + 45’ |
> gregorian Date > tmp
```
```text
mv tmp project
```
```text
Difference
You can also find the difference between two dates.
```
For example, a building contractor may have a table called house, which contains the start dates and stop dates for each phase of building a home:
Start Stop Days Step
```text
890101 890118 Lay concrete
890121 890212 Setup frame
890215 890302 Build walls
890305 890401 Install fixtures
890408 890425 Sell at a loss
```
To compute the number of days for each step. we can use the julian and gregorian programs on the house table:
```text
julian Start stop < house |
compute ‘Days = Stop - Start’ |
gregorian Start Stop > tmp
```
```text
mv tmp house
```
house now appears as follows:
Start Stop Days Step
```text
890101 890118 17 Lay concrete
890121 890212 22 Setup frame
890215 890302 15 Build walls
890305 890401 27 Install fixtures
890408 890425 17 Sell at a loss
```
*— PDF-Seite 125 · Buchseite 115 —*
Formats
There are a number of different formats that people use to express dates. The julian and gregorian programs also allow you to convert between three different formats.
Computer Computer date format is YYMMDD. For example, January 31, 1989, translates to "890131". This format is best because it can be sorted, and is the most compact. You can also test to see if one date is greater than another. Most users can quickly get used to it.
US In the United States, dates are written in the sequence MMDDYY. For example, January 31, 1989 translates to “1/31/89”.
```text
European
The Europeans use the sequence DDMMYY. For example, January 31, 1989,
translates to 31/01/89.
```
Conversions
The /rdb commands julian and gregorian let you convert dates from one format to another. Simply specify the current format to the julian command and another format that you want to the gregorian command, and the format will change. The default format is computer format.
```text
For example, let's change the computer format in the project table to US format:
julian Date < project | gregorian -u Date
```
project now appears as follows:
```text
Date Description
6/01/89 Start project
7/01/89 Project crises
8/01/89 Abandon project
9/01/89 Coverup blame
10/01/89 Write off losses
```
You can see one of the problems of the standard date is that it is eight characters. Since the tabs are also eight characters, the next column has to move over. You can use the justify command to pretty things up:
```text
julian Date < project | gregorian -u Date | justify Date
project now appears as follows:
```
```text
Date Description
6/01/89 Start project
7/01/89 Project Crises
8/01/89 Abandon project
9/01/89 Coverup blame
```
10/01/89 Write off losses
*— PDF-Seite 126 · Buchseite 116 —*
## Set-Theory Commands
In addition to the basic relational commands, there are several that come from relational set theory.
## Concatenating Tables
The union command appends one table to another, making a larger table consisting of all of the rows of each.
For example, consider a set of accounting tables. The first table is called journalcash:
Date Account Debit Credit Description
891222 101 25000 cash from loan
891223 101 5000 cash payment
```text
891224 101 15000 cash payment to CCPSC for parts
The second is called journalloan:
```
Date Account Debit Credit Description
```text
891222 211.1 25000 loan number #378-14 Bank Amerigold
891223 211.2 5000 note payable to Zarkoff Equipment
And the third is called journaladjust:
```
Date Account Debit Credit Description
891224 130 30000 inventory - parts from CCPSsCc
Note that all three tables consist of the same set of columns.
Now, we use the union command to consolidate these subsidiary journals to create a general journal:
union journalcash journalloan journaladjust \> journal
Table journal appears as follows:
Date Account Debit Credit Description
891222 101 25000 cash from loan
891223 101 5000 cash payment
```text
891224 101 15000 cash payment to CCPSC for parts
891222 211.1 25000 loan number #378-14 Bank Amerigold
891223 211.2 5000 note payable to Zarkoff Equipment
891224 130 30000 inventory - parts from CCPSC
```
*— PDF-Seite 127 · Buchseite 117 —*
## Subtract One Table From Another
The command difference lets us subtract one table from another to give the rows that are in the first table but not in the second table.
For example, the following command finds the difference between two of the abovedescribed tables:
```text
difference journal journalloan
```
This prints the following on the standard output:
Date Account Debit Credit Description
891222 101 25000 cash from loan
891223 101 5000 cash payment
```text
891224 101 15000 cash payment to CCPSC for parts
891224 130 30000 inventory - parts from CCPSC
Intersect Between Tables
```
The command intersect lets us find the rows that are in both tables, the intersection of the set.
For example, the following command finds the intersection between two of the above tables: intersect journal journaladjust
It prints the following on the standard output:
Date Account Debit Credit Description
891224 130 30000 inventory - parts from CCPSC
*— PDF-Seite 128 · Buchseite 118 —*
*— PDF-Seite 129 · Buchseite 119 —*
# Section 12 — Combining /rdb with COHERENT
Much of your data-base work can be done with COHERENT commands. Many of the traditional problems of data bases disappear when you have a COHERENT system. If you have only one or a few users, problems like security, distributed data, concurrent access to files, backup, checkpoint and recovery, validation, audit trails and logging, and others, are minimized.
This chapter gives suggestions for combining /rdb with COHERENT tools to develop solutions to these problems. This is not to say that there are no longer any problems. There is still a role for programmers and system/analysts. But it is important for these professional people, who got their experience on older systems, to re-think what they know in light of the new tools and the new economics of our changing technology.
## Multi-User Concurrent Access to Files
On small systems, you can assign each file to only one person. Then only one person need access it at a time. Any number can append new records to a file at one time with the enter command. Also, any number of users can read a table into their /rdb and COHERENT commands, since reading does not change the table.
The only problem that arises is when two or more people must edit a table or list file at the same time. Files can be locked in several ways. There is a lock and an unlock command for this purpose. With the blank and replace commands, you can blank out a record while you have it out for edit. The update commands does this.
Each user can move (mv) the file to a new name before editing it. Perhaps they might move it into their own directories, make their changes and move it back. That way other users will not find the file when they try to edit it. This is how the vilock command works. Application programs can change the permission of a file so that it is read only to others on the system, when our user is updating it.
There are also the lock and unlock commands, which are shell scripts to show how easy it is to solve this problem with COHERENT tools.
## Screen Form Entry
If you want to put forms on the terminal screen for the users to input data into, you can use ve or the screen program. screen takes a form you create in a text editor, as with the report command, and creates a shell script that will display the form. read the user's input and output a table. Because it is a shell script, it can be edited to do a lot more including validation, table lookup, and others. ve also takes a form, like the report command's form, and creates a table.
*— PDF-Seite 130 · Buchseite 120 —*
Security
You can handle security by physically protecting the computer and the terminal, by using the COHERENT security permissions on files and directories, and by encrypting files. ve contains special security features like unwriteable and invisible fields. There are read, write, and execute permissions for the owner of the file. the group, and anyone on the computer. See the COHERENT commands chmod and crypt.
Backup
You should backup the /rdb tables and list files just like regular COHERENT files. You can simply copy a file or a whole directory to a backup media like magnetic tape, cassette tape, or floppy disk, or transmit to another computer for backup. The COHERENT ustar and cpio commands can be used for putting an entire directory structure into a single file.
## Checkpoint and Recovery
You can always create a copy of a file that you are working on. /rdb commands do not alter their input files. They simply create new files or pass their output (pipe) to another program. In a crash, the original file is not harmed. Only the editors modify the existing file and at least one. vi, has a crash recovery system.
Validation
ve provides programmable validity checks for data as it is entered. awk scripts and other programs can be developed to check the validity of operator input. The vi editor has the ability to assign to a single key a complex program. It can be used to validate each line typed. The /rdb command validate is available to do any data validation from simple to complex. See the sections on validation in the /rdb manual and the ve chapter.
```text
Audit Trails and Logging
This is very easy because of the diff command.
At the end of each day's work the diff program can be run like this:
diff todaysfile yesterdaysfile > todayslog
```
The file todayslog will contain all lines that have changed since yesterday. Save it and you have a log or audit trail. It can also be used for recovery to any date in the past.
*— PDF-Seite 131 · Buchseite 121 —*
# Section 13 — Other Data-Base Systems
Many data-base management systems are available. Each has its strengths and weaknesses. However, they usually take a traditional approach. Such systems were developed on operating systems that provide only a fraction of the services that COHERENT provides. Therefore, the data-base developers had to write as much functionality into their data-base packages as they could. When these data-base management systems are moved to the COHERENT environment, they require that you leave COHERENT tools and all of their power behind, and go into a software box where you are limited to the functions that the data base developers have supplied.
There are many other data-base packages running on COHERENT systems, but they all take this traditional big box approach. One usually finds that functions COHERENT tools could provide are not available inside those data-base system boxes. There is usually no good way to get the data out to COHERENT and back. It was the frustration of knowing that we could do what we needed to do with COHERENT tools, but that our data was locked up in the data base package, that originally prompted the development of /rdb.
With /rdb you always have access to the full power of the COHERENT system, because /rdb commands are COHERENT commands that can be piped together with other COHERENT commands. They extend the power of COHERENT tools rather than waste it. /rdb works at the shell level and allows you to use all of the COHERENT utilities and powers. With shell programming you can build applications easily with both COHERENT and /rdb commands mixed and piped together.
With other data-base systems, you must learn a whole new language/syntax that is unique to that data-base package. Learning /rdb is learning the COHERENT system, which is useful in many applications. Or you can use the COHERENT knowledge you have already acquired. In fact. it is an excellent way to learn COHERENT tools, just as many people learned computers starting with a spreadsheet program.
## Resource Use
When conventional data base systems duplicate COHERENT functions, programs become huge. These programs take up tremendous amounts of computer memory and other resources. Most data base packages will severely impact even large expensive computers with only a few users. By doing things the COHERENT way, only the small programs that are needed are brought in from the disk, putting only a light load on the system. This can save hundreds of thousands of dollars in computer hardware, to say nothing of software.
## C Programming Unnecessary
The COHERENT system has many programming languages, including the C language. Although many programmers naturally think they must use such programs in their work, it is usually unnecessary. Putting together COHERENT programs will usually accomplish whatever is needed.
Although much can be done with the basic COHERENT system as delivered, some database facilities and tools are missing or are hard to create. Therefore, a number of relational data-base management systems have been developed for the COHERENT system.
*— PDF-Seite 132 · Buchseite 122 —*
Unfortunately, most come from other operating systems and ignore the power of COHERENT. On other operating systems, virtually nothing exists to help the developer and user. Everything must be programmed from scratch. If the developer or the user is to have a feature, it must be programmed into the data base program.
On COHERENT the reverse is true. Much of what you need is already available in the COHERENT environment. The traditional data base management systems, when moved to COHERENT, discourage the developer and user from getting access to these powerful and familiar COHERENT tools. It is as if these systems create an unfamiliar box that you must go into, leaving the power of COHERENT behind.
/rdb, however, was built for the COHERENT environment. It consists of over 100 COHERENT-like commands that fit together nicely with other COHERENT commands. It has the tools that were found to be needed from real experience of developing software applications. Using COHERENT shell programming, developers can quickly put together applications from both COHERENT and /rdb commands. Users face a unified environment. They may not know or care whether the commands they use come from the COHERENT system or /rdb. This is the correct way to extend the COHERENT system: keeping the power and genius of the COHERENT system and adding functions to it.
Speed
Most of the research on data bases and their problems assumes that you have huge files, need to find a record (row) very quickly, and have many users. Not many years ago. few could afford to have the power that a microcomputer offers today. Then computers cost millions of dollars and had to be shared by many users. Only large volume applications were cost effective enough to computerize, leading to a tremendous concern for speed and size. Early eight-bit microcomputer systems reinforced this thinking. With weak computers, small memories. and floppy disks, size and speed were still overriding issues.
Today, and more so in the future, we have powerful 16- and 32-bit microcomputers with large memories and big disks, but so inexpensive that they are ubiquitous. Applications will run faster and handle larger data bases. Now we want ease of use and powerful systems. The bulk of data base applications are for relatively small data files of a few hundred to several tens of thousands of records, with a small number of frequently asked queries. If you think of something new to do that was not planned for in the development of the application, you will usually find it very difficult or impossible to do. These traditional data bases often require complicated setups. lots of training to use and are difficult to modify. Worse still, they are huge programs that take up much of the memory and CPU cycles of the computer. Only a few users can slow a big expensive computer down to an unacceptable response. These traditional data base systems have features built into a large program. The COHERENT system has lots of features, but they are in the hundreds of programs stored on the hard disk. COHERENT only brings in the code it needs for a particular function. The average COHERENT utility is about 40 kilobytes. Traditional data base programs are often a quarter of a megabyte and larger.
/rdb takes a much different approach. It is much closer to the ideas of a text editor, spreadsheet and, of course, the COHERENT system. It handles small data bases as well as large. /rdb is aimed at ease of use and maximum power. Even so, it is usually very fast. But when more speed is needed, /rdb also has not one but five fast-access methods to give a variety of ways to access large files. /rdb is as fast or faster than most other data base management system. Furthermore, even grep with its sequential search is not so bad. grep is a COHERENT program which looks for a string pattern and prints out each line in which it finds a match. Remember that there is computing overhead for the traditional fast access methods. Binary searches require sorting, hash tables must be computed, B-trees must split their pages when they fill, linked lists must maintain their pointers, and so on.
*— PDF-Seite 133 · Buchseite 123 —*
Size
As the size of our tables diminishes, so do the advantages of the fast access methods. bm, an implementation of the Boyer-Moore linear search algorithm that is quite a bit faster than grep but limited to fixed strings (not patterns), is distributed with /rdb. in the S$RDB/Llib directory.
Many data-base comparisons put great emphasis on the size of the data base that can be handled. This is really a problem for data-base systems that are one large program. /rdb, however, is a group of small programs which can be piped together. Its only limits are those of your hardware and COHERENT itself.
A table can be as big as the available free space on your disk, or as big a file as your COHERENT system can handle. Use the COHERENT commands df to see how much space is left on the disk, and use the COHERENT command du to see how much disk space a given directory uses. For details, see these commands’ entries in the Lexicon.
*— PDF-Seite 134 · Buchseite 124 —*
*— PDF-Seite 135 · Buchseite 125 —*
# Section 14 — Can You Say that in English?
If you are not a mathematician, you may find the literature on relational data bases to be incomprehensible. One problem is the terms used in the literature. Different terms are used by the mathematicians, computer people, and other humans.
We try to use human terms throughout the /rdb documentation. We lapse into computer terms either by mistake, or when we think we are talking to programmers and analysts about the more technical details. We ignore the mathematicians, since they seem to ignore us. But we love them. Without them we would not have relational theory. Here is a table that will help each group translate terms used by another group:
```text
Humans Hackers Mathematicians
table....
```
```text
number of columns.
number of rows
list of tables..
user's tables.
```
```text
one concept per table.
get rows
get column
combine tables
new command...
```
## Data-Base Models
A data-base model is a way of structuring and thinking about data. We use the relational model, but there are several others. There are three major types of data base models that have been implemented in several commercially successful data base management systems: relational, network, and hierarchical. In addition there are at least four more important models discussed in the literature, but for which few implementations exist as yet: entityrelationship, binary, semantic network. and infological [Tsichritzis. 1982]. We will probably see more of them in the future.
The major difference between these models is their structure. As you read through these descriptions, you will probably have a sense of deja vu. Each is quite similar to the other with some differences. Remember that information in each model can be converted or transformed into the other models.
*— PDF-Seite 136 · Buchseite 126 —*
Hierarchical
The hierarchical data base has a tree structure. (In computer science, trees have their roots at the top and grow their branches and leaves downward.)
This type of data base was popularized by IBM. Their IMS data-base management system has been widely used in the past. When the users build a data base, this structure must be imposed upon their data. Some searches are speeded up (such as from classes to grades). Others become difficult or impossible. e.g., What grades did an instructor give? The emphasis is on speedy responses from older, slower, and usually heavily burdened computers. The speed is achieved by anticipating standard searches and optimizing them. But ad hoc queries (ones you just think up as you are working) are not only slow, but are often difficult, even impossible, to do.
Network
The network type of data base has a two-level structure. Both Total and Image/Query are examples of this approach. This model comes from a CODASYL committee standard. This system is a little easier to build and use than hierarchical, but still requires that the user know the structure and navigate through the links. It is difficult, if not impossible to get from one detail file to another.
Relational
Relational data bases have what are called a flat file structure. All files are at the same level. With such a structure and a set of commands like project, select, and join, one can get all of the information out of the data base that has been put into it.
E. F, Codd of the IBM San Jose Research Laboratory proposed this relational model in the early 1970s [Codd 1970]. Since then, the relational approach has captured the attention and approval of most of the academic, and now business, researchers in the field. IBM is converting to relational with its new System R data base management system. It uses SQL for a user interface. Almost all of the data-base systems that have been built for COHERENT are relational.
A relational data base management system is considered by most researchers in the field as the best for several reasons. Relational data bases have a solid mathematical base in relational set theory, relational algebra and relational calculus. There are theorems in this relational mathematics that prove that any data put into a relational data base can be extracted. The mathematical base also assures us that the manipulations we perform will have correct results, just as arithmetic assures us that the mathematics functions we perform on the computer have correct results.
The relational structure is the simplest. All information is kept in simple tables. The user does not have to navigate through complex networks (network model) or tree structures (hierarchical model). Relational theory has tables (relations) with rows (tuples) and columns (attributes of domains), which anyone can understand.
It also has functions on tables: project (column), select (row). join (jointable), and so on. These functions both input and output tables, just as the functions in algebra which we are familiar with input and output numbers (scalars), lists of numbers (vectors), or arrays of numbers (matrixes). These commands we've discussed earlier. They are the most frequently used.
*— PDF-Seite 137 · Buchseite 127 —*
There are also several commands from set theory that are not as often used but are important for completeness. There has been a lot written on relational data base systems and theory. See the Bibliography.
Entity-Relationship
The entity-relationship model was put forth by Chen [Chen 1976]. This model sees the universe, or more practically the company or institution, as composed of entities and relations between them. Things, people, departments, and so on, are entities. Entities have relationships between them. A department is part of an enterprise. People work in departments as staff members. Equipment is assigned to departments. Some people are heads of departments. One can draw a diagram of these entities and relationships.
There is a one-to-many relationship. A department can have many staff people and many pieces of equipment. But each employee and piece of equipment is assigned to only one department. If the rules of the organization change, so will this graph.
This model has similarities to the three classic models. The relational model holds entities in tables (also called relations). It provides the jointable command to combine tables on keys in which. there is a relationship between the entites of one table and another. It can also be seen as hierarchical and network because of the structures. This model trys to capture the overall structure of the enterprise regardless of how it is implemented. It is the big picture.
Binary
The binary model sees data as a graph in which each node is a simple column or field of data and the arcs that join the nodes represent simple relationships between them. It is based on graph theory. As we move to computer systems with powerful graphic screens, this model might become more common.
## Semantic Network
The semantic-network model comes from the field of artificial intelligence (Al). (See Quillian [1968] and Sowa [1983]). Al is the part of computer science that trys to get computers to be intelligent. Its subfields are games, expert systems, vision, robotics, natural-language recognition, and others. Researchers came up with this model in trying to structure data for these efforts, trying to understand the human associative memory. and trying to understand natural language.
There are many variations of the semantic network model because many researchers have written about different versions in the technical literature. In the broadest sense any graph model is a semantic network model, including the entity-relationship and the binary model.
The new graphic terminals will make this graph model easier to display and input. Since all information can be represented in this way, it will be a very powerful way to interact with computers.
Infological
An infological model is the user's view of the application. There is a dream that some day a user can simply communicate the structure of the application to the computer and the data base system will be set up automatically — somewhere between a general data-base management system and a specific application. Some elements exist today. The new graphic terminal systems provide powerful tools to communicate with the user and give the user the ability to specify needed applications pictorially. Work in this field will be fun and
*— PDF-Seite 138 · Buchseite 128 —*
```text
productive for future users.
```
## PROLOG: Programming in Logic
Finally, the PROLOG language adds logic programming on top of a data base model. PROLOG is discussed more in the next chapter.
## The Grand Unified Field Theory of Information
The Grand Unified Field Theory of Information is that all of the different structures of information are simply transformations of each other. Natural language sentences and their parses, predicate calculus, tables and relational algebra, graphs, and semantic networks are simply different representations and transformations of information.
Each has its advantages and uses. People speak language and understand graphs. Computers can parse language, store tables, and manipulate them through relational algebra and predicate logic. Sentences can be converted to predicate calculus formulas and solved by comparing with the table data base.
This offers enormous power and possibilities. In the years ahead the written literature of many fields can be scanned by computer, parsed, and inserted into tables. Then written or spoken queries can be parsed and converted into predicate calculus formulas which can be evaluated against the relational table data base. The computer can then speak, write, or draw a graph or a picture of the answer.
*— PDF-Seite 139 · Buchseite 129 —*
# Section 15 — PROLOG and Al
Artificial-intelligence programs, like most programs, rely heavly on data bases. /rdb has several facilities to assist Al, and especially expert system programs.
## PROLOG Language and Environment
PROLOG is a programming language that allows you to program in logic. It was developed in Europe, and has been adopted as the language for the Japanese Fifth Generation Computer project. It is used in artificial intelligence work. It provides a powerful new method to make logical inferences from data bases. Instead of being able to find data only, it can reason from that data to answer questions that are not in the data base, but are logically derivable from the data. This is an enormous leap in getting the computer to be smart.
PROLOG is an entire programming language and environment, mainly because it was developed on non-UNIX operating systems where almost nothing was provided. But we are only interested in the logical searching features which are its major contribution. The logic programming of PROLOG would be best placed in a UNIX/COHERENT environment with its many tools, rather than in the primitive PROLOG environment.
If you are interested in working with PROLOG, COHware volume 2 contains, among many other items, the source code for a PROLOG interpreter.
## Predicate Calculus
The branch of logic that PROLOG uses is predicate calculus. This is not the calculus you learned in math classes, but refers to the manipulation of formulas, of which the calculus you are familiar with is only one form.
Almost all sentences in a natural language can be converted into predicate calculus statements and manipulated logically. The sentence: Bill loves Kathy is written: loves(Bill, Kathy). This says that there is a relationship, love, and that the first argument, Bill, has that relationship with the second argument, Kathy. This predicate calculus formula can also be expressed as a table:
Subject Object
Facts
PROLOG stores facts in the predicate calculus notation. Since almost any sentence can be expressed, almost any information can be stored in the data base.
*— PDF-Seite 140 · Buchseite 130 —*
```text
PROLOG Means
female(michele).. .-michele is a female
female(jane).
```
male(john)...
```text
male(shawn)... shawn is a male
```
```text
..Shawn is a parent of jane
michele is a parent of jane
```
```text
parent(shawn, jane).
parent(michele, jane)..
```
These facts are entered into PROLOG by simply typing them in or having PROLOG get them from a file with the PROLOG consult command.
Questions
Once the above data are entered into the PROLOG data base, you can ask questions. The following gives a sample PROLOG “question time” — the user's questions appear in Roman, and PROLOG's replies in italics.
```text
parent(shawn,jane)
yes
```
```text
female(shawn)
```
```text
no
mother(michele,jane)
no
```
The first query is found in the data base and yes is returned. The second and third queries are not found in the data base, so no is returned. None of this is very exciting because any data-base management system can do this. However, we humans know that the third query is true because we know that if michele is the parent of jane and that michele is female, then michele must be the mother of jane. But no data base can know this rule and logically deduce this conclusion except PROLOG.
This great innovation of PROLOG comes when we add rules and logical inference to the data base of facts. A rule is stated in this form:
mother(X,Y) :- parent(X,Y), female(X).
In English this rule says that the relationship mother exists between two entities X and Y if (:-) X is the parent of Y and (,) X is a female. This rule is stored by PROLOG. Now we can ask again:
```text
mother(michele,jane)
yes
```
This time PROLOG gives the right answer. Not because it found the fact in the data base, but because it inferred the fact from facts and rules in the data base. PROLOG failed to find the fact in the data base, so it searched its list of rules for one that started with mother. It then assigned michele to X and jane to Y. It went to the facts after the if (:-) symbol. PROLOG first looked for the fact parent(michele,jane). It found that successfully, so it then searched for the fact female(michele). This was also successful, so it responded with yes.
With a simple mechanism. we now have the ability to logically infer facts from other facts and rules!
*— PDF-Seite 141 · Buchseite 131 —*
```text
/rdb Interface to PROLOG
```
/rdb provides an interface to PROLOG with two commands: tabletofact and tabletorule. These convert /rdb tables into the predicate calculus formulas that PROLOG needs to see. Therefore, we can logically query our data base.
```text
tabletofact
```
The tabletofact command converts a table to predicate calculus. First let's look at our /rdb fact tables. First. table female:
```text
michele
beth
sandy
jan
```
```text
Table male:
Male
```
```text
kirk
rod
shawn
durk
```
```text
Table parent:
Parent Child
```
```text
michele rod
```
```text
kirk rod
```
```text
And finally, table isa:
Name Isa
```
```text
rod human
```
```text
human mammal
mammal animal
animal lifeform
```
```text
Now let's convert them all to PROLOG fact format.
tabletofact female male parent isa > fact
```
File fact appears as follows:
*— PDF-Seite 142 · Buchseite 132 —*
```text
female(michele).
female(beth).
female(sandy).
female(jan).
male(kirk).
male(rod).
male(shawn).
male(durk).
```
```text
parent (michele, rod).
parent (kirk,rod).
isa(rod,human).
isa(human,mammal).
isa(mammal,animal).
isa(animal,lifeform).
```
```text
tabletorule
```
Rules can also be stored in /rdb tables and converted to PROLOG format with the tabletorule command. For example, consider table ruletable, as follows:
True If
```text
mother (X,Y) female(X) , parent(X,Y)
father (X,Y) male(X) , parent(X,Y)
son(X,Y) male(X) , parent(Y,X)
isa(X,Y) isa(X,Z) , isa(Z,Y)
```
The command
```text
tabletorule ruletable > rule
```
writes the following into file rule:
```text
mother(X,Y) :- female(X) , parent(X,Y).
father(X,Y) :- male(X) , parent(X,Y).
son(X,Y) :- male(X) , parent(Y,X).
isa(X,Y) :- isa(X,Z) , isa(Z,Y).
```
Then you can consult these files within PROLOG with the consult command.
Now you are ready to ask questions. With this data base you can now ask questions about motherhood and fatherhood, and questions like is rod a lifeform?
## Problems of PROLOG
Richard Forsyth [Forsyth 1984, page 16] lists many complaints about PROLOG. These include the following:
```text
“PROLOG provides a relational data base for free — a big bonus, but the trouble is that It
resides in main memory, and ts consequently very greedy on storage.”
```
He also quotes Feigenbaum and McCorduck [1983]: “The last thing a knowledge engineer wants Is to abdicate control to an ‘automatic’ theorem-proving process that conducts massive searches without step-by-step control exerted by knowledge in the knowledge base.”
*— PDF-Seite 143 · Buchseite 133 —*
The reason for all of the problems in PROLOG is that it is a great idea and a programming environment. On non-COHERENT systems, when you want to do something, you wind up having to do everything else also. You have to write editors, floating-point handlers (some PROLOGs don't), trace, input/output, and on, and on. In addition, both PROLOG and LISP do everything in memory. This is fine for small prototype and demonstration programs in a university Al research lab, but unworkable for large data bases.
The same is true for LISP. Peter Jackson [Jackson 1986] writes about a classic expert system: “The difference between MYCIN's score and those of Stanford experts was not significant, but its score Is as good as the experts and better than the non-expert physicians. However, MYCIN is not currently used in wards for a number of reasons ... it is written in INTERLISP, is slow and heavy on memory ..."”
This problem is not new to the computer world. It was solved decades ago in commercial computing. There needs to be a shift from memory to secondary storage as AI moves from the research labs to real users. See Expert Database Systems: Proceedings From the First International Workshop [Kerschberg 1986].
We also need to shift from PROLOG and LISP to UNIX/COHERENT and a powerful database management system like /rdb. As radical as this sounds, one of the leading expert system companies converted its system from LISP to COHERENT and C. They got a fiftyfold increase in speed! The other expert-system companies are in various stages of converting to UNIX.
On UNIX/COHERENT, you can simply add a new capability to an excellent environment. PROLOG's environment is quite primitive and its inference system narrow and limited. The PROLOG rule inference and search mechanism should be added to COHERENT as simply more programs. We expect to see all of the Al ideas added to COHERENT in the years ahead. We should see different logics, that is, fuzzy logic, Bayesian logic, multi-valued logic and certainty factors. We should also see many new search strategies. Heuristic searches guided by data in the data base are needed. Then we will see many new expert systems developed with these vastly enhanced tools.
By concentrating on only what is new, developers can do a much better job. They won't have to waste most of their time reinventing environment wheels.
```text
searchtree: Data-Base Tree Searching
```
Most AI programs search data bases that can be visualized as trees or networks. Speeding those searches and controlling them is a very important area of research. Usually, these trees are kept in memory and searched with pointers. This limits the size of the data base that a LISP or PROLOG program can handle. It is not as fast as one might imagine. Memory searches are fast, but the overhead of bringing the data in off the disk, and hogging so much memory that programs must swap frequently, quickly wipes out any theoretical speed advantage.
searchtree is a /rdb shell program that shows another way to search a tree. It can use the fast access methods to do a breadth first search of any sized data table. It is a shell program example which can be edited to handle many search situations. Heuristics can be built into the code to speed, or otherwise improve, the performance of the search.
*— PDF-Seite 144 · Buchseite 134 —*
*— PDF-Seite 145 · Buchseite 135 —*
# Section 16 — /rdb and C
You can call COHERENT and the /rdb data-base commands from C programs. This chapter gives you several example programs starting from the most simple to the most complex.
## Don’t Do It
Before we start, it is strongly recommended that you think twice before writing C or other language programs. The shell, COHERENT tools, and /rdb commands are so powerful. fast. and easy to develop, you seldom need to bother with the old third-generation programming languages. If you think of writing a program in C by habit, try to break the habit. Always try to do things in the COHERENT shell and /rdb first. Only resort to C when there is a compelling reason. as opposed to a compulsion. We consider resorting to C as a failure of imagination, or lack of knowledge or insight. in most cases. If you think you need a C program, you may really need to know more shell programming tricks. Think of your problems as a more general problem, and check to see if there is a COHERENT or /rdb program that will do the job.
Speed is the most common excuse for descending to C coding. Remember that computers are getting faster and cheaper. The RAM disk can greatly speed up COHERENT programs. Also. try using the shell to implement a prototype. You can see if it is too slow before coding. Often our intuitions are wrong in these matters. Also, the users might change their minds and decide on a different way to approach the problem. Your prototype will then have saved you a lot of unnecessary C coding.
If you do descend to C, try to write small programs that can be used in future shell programming. Only write what you need. Read from the standard input and write to the standard output. Make your programs table driven and use /rdb data-base table and list formats so that the full power of COHERENT and the data base can manipulate the tables that drive your programs.
system(): Tell Shell to Execute a Program
The easiest way for C programs to access both COHERENT and the /rdb data base is with the COHERENT function system(). It only needs a character string, or pointer to a character string that contains a shell command. system( will execute the command, just as though you typed the command at the terminal or entered it into a shell program.
```text
In the example below are three different ways of setting up the command string:
#define COMMAND “ls | we"
```
*— PDF-Seite 146 · Buchseite 136 —*
```text
main (argc, argv)
int argc;
char *argv [];
```
```text
{
system ("echo hello word");
system (COMMAND) ;
system (argv [1]);
```
```text
}
```
The first call to system( hard-codes the command in the code of the function call. The second call uses a previously defined name COMMAND. Note the line
```text
#define COMMAND
```
at the beginning of the code. Finally, the first argument on the command line is used as a command string for system():
```text
system (argv [1]);
This allows the user to type a command as the first argument and it will be executed.
```
The COHERENT command make is used to compile the program. It uses the Makefile, whose contents are as follows:
```text
system: system.o
cc system.o -o system
```
```text
Thus, typing the command
make system
prints the following on the screen:
```
```text
cc -O -c system.c
cc system.o -o system
```
This shows the steps COHERENT uses to compile and link your program. (For a full description make, the programmer's best friend, see its tutorial in your COHERENT manual.)
Now that the system program has been compiled, it can be run with a command as an argument:
```text
system date
This produces something like:
```
```text
hello word
% 7 65
Thu Apr 3 02:10:04 PST 1986
```
Note that the first system call produced the hello world line. The second call executed the defined command
```text
ls | we
```
Note the output on the second line probably will differ on your system.
*— PDF-Seite 147 · Buchseite 137 —*
Finally, the date and time were displayed when the date argument to the system program was executed by the call to system().
```text
execl(): Execute a Call
```
The next step from simple to complex is the execl() function. This function will replace the current process with another program. It is usually called chaining. Once called, the calling process dies and is never reentered. The executed program takes over the process table entry of the calling program and all of the open input and output files. Here is an example.
```text
#include
#define FIRST"First"
```
```text
char *pl = "argument";
char *p2;
```
```text
main (argc, argv)
```
```text
int argc;
char *argv [];
{
p2 = “is:";
```
```text
fflush (stdout);
execl ("/bin/echo", “echo", FIRST, pl, p2, argv[1], NULL);
¥
```
```text
When we run the command
execl ARG1 ARG2
we see:
First argument is: ARG]
```
All of the arguments to execl( are pointers to strings; you can have as many as you want. The last one must be NULL, as a sentinel or end marker.
In the first argument, the full path to the program to be executed must be given because execl() does not search the PATH environmental variable. It is not good to hard code paths.
The second argument is the zero’th argument. which is the name of the called program. The rest of the arguments are the normal arguments as you would type on the command line at the shell level. Several possible ways of setting up the arguments are shown. The first regular argument is a defined constant. p1 and p2 are each pointers to strings. The first is initialized to a string when it is declared and the second is assigned later in the code. Finally, the first argument passed to the calling program is passed on through the second pointer in the argv array of pointers.
```text
execi() Shell Programs
```
If you try to use execl() to execute a shell script file. it will fail. You have to execute a sh shell program to read the text of the shell file. Here a shell file called istargs is executed. It simply echoes out its arguments separated by newlines:
*— PDF-Seite 148 · Buchseite 138 —*
fork():
```text
for I in $*
do
```
```text
echo $I
done
```
Now, the program execl.sh.c, which executes listargs via execl():
```text
#include
#define FIRST "First"
```
```text
char *pl = “argument";
char *p2;
```
```text
main (argc, argv)
```
```text
int argc;
char *argv [];
{
```
```text
p2 = “is:";
```
```text
fflush (stdout);
execl ("/bin/sh", "sh", “listargs", FIRST, pl, p2, argv[{1], NULL);
```
```text
}
```
```text
When executed with the command
execl.sh argl
```
you see:
```text
First
argument
is:
```
```text
argl
```
Note that sh is the program executed, and that its first argument is listargs. This is like typing: sh listargs
## Create a Child Process
Sometimes we want to run another program without killing ourselves. The system call fork( creates a child process that is identical to the calling program. The return value of the fork() command can be tested to see which process the code is in, parent or child. Therefore, the same program, with the same code, can branch to different statements, depending upon whether it is the parent or child process. The child code can do its thing, including executing another program. The parent process can wait for the child to finish before going on. But it does not have to, because the COHERENT system is a multiprocessing environment.
The following program, fork.c, gives an example of using fork( in a C program:
```text
#include
```
*— PDF-Seite 149 · Buchseite 139 —*
```text
#define FAIL -1
#define CHILD 0
#define PARENT 1
```
```text
main (argc, argv)
```
```text
int argc;
char *argv [];
{
```
```text
switch (fork()) {
```
```text
case -1: /* error */
fprintf (stderr, “fork system call failed.\n");
exit (FAIL);
```
```text
case 0: /* child process */
execl ("/bin/echo", "echo", "I am the child.", NULL);
exit (CHILD);
```
```text
default: /* parent process */
if (wait(NULL) != -1) {
fflush (stdout);
printf ("I am the parent.\n");
} else {
fflush (stdout);
fprintf (stderr, “wait system call failed.\n");
```
```text
}
```
```text
exit (PARENT);
}
```
When this program is compiled and invoked, you see the following on the standard output:
```text
I am the child.
I am the parent.
```
This example uses the C switch() keyword execute fork(), because it has three different return values. A -1 return indicates a failure to fork a new process. Perhaps the number of processes has reached a limit. We want to handle this error condition.
A zero return means that the code is now in a child process, so the code should do the child's thing. In this case, the child process executes an echo command with execl(). Thus. it changes into another program.
Finally, the parent process gets the child's process ID number, which is some number greater than zero. Here the parent waits for the child to die before printing its message. It flushes the standard-out buffers before printing its own message.
You can see when we execute this program, both processes write to the standard output.
*— PDF-Seite 150 · Buchseite 140 —*
Pipes
A very important use of this mechanism is to use the pipe() system call to open a pipe between the two processes so that they can exchange data. This can go either way. from parent to child, or from child to parent.
## One-Way Pipe
The first example here is of a one-way pipe. The next section will demonstrate a two-way pipe.
```text
#include
```
```text
#define FAIL -1
```
```text
#define CHILD 0
```
```text
#define PARENT 1
```
```text
#define MESSAGE “Hi, kid"
```
```text
main (argc, argv)
```
```text
int
char
```
```text
{
```
```text
arge;
‘argv [1];
```
```text
int pd [2];
char childbuf [BUFSIZ];
```
```text
if (pipe(pd) == FAIL) {
fprintf (stderr, “pipe system call failed.\n");
exit (FAIL);
```
```text
}
```
```text
switch (fork()) {
```
```text
case -1l: /* error */
fprintf (stderr, "fork system call failed.\n");
exit (FAIL);
```
```text
case 0: /* child process */
if (close (pd [1]) == FAIL) {
fprintf (stderr, “close pipe failed.\n");
exit (FAIL);
}
```
```text
read (pd [0], childbuf, BUFSIZ);
execl ("/bin/echo", “echo",
```
```text
“child read:", childbuf, NULL);
exit (CHILD);
```
*— PDF-Seite 151 · Buchseite 141 —*
```text
default: /* parent process */
if (close (pd [0]) == FAIL) {
fprintf (stderr, “close pipe failed.\n");
exit (FAIL);
}
```
```text
printf ("parent wrote: %s\n", MESSAGE, sizeof (MESSAGE) );
if (write (pd[1], MESSAGE, sizeof(MESSAGE)) == FAIL) {
fprintf (stderr, “pipe write filed\n");
exit (FAIL);
}
}
exit (PARENT);
}
```
When compiled and run, this program prints the following on the standard output:
```text
parent wrote: Hi, kid
child read: Hi, kid
```
pd is the pipe-descriptor buffer, which holds two integers, one for each pipe direction. The parent writes into pd[1] and the child reads from pd[0]. Each closes its other pipe with the system call close(). fork() creates the child process. The parent process writes its message to the pipe with the system call write(). It used the C sizeof operator to count the characters of the MESSAGE. This allows us to edit the message and not have to look through the code to find, count and change its size.
The child process reads the pipe with the system call read() and executes the echo command to display the message it got from the parent process.
Of course this is not very useful, but it is simple enough to follow. It can be used in any situation in which we want to crank up a background process and periodically send it data to act upon. This mechanism is especially useful in COHERENT because there are so many programs that are available to save us the effort of writing them.
## Pipe to Standard Input
In the example above, write() was used to read the pipe and the message was passed on to the executed echo program as an argument. But we also want to write to the standard input of a COHERENT program. In the example below, the child executes a process that reads from its standard input. The child connected the pipe to its standard input using the system call dup():
```text
#include
```
```text
#define FAIL -1
```
```text
#define CHILD 0
```
```text
#define PARENT 1
```
```text
#define PM “Hi, kid"
#define cM “Hi, parent"
```
*— PDF-Seite 152 · Buchseite 142 —*
```text
main (argc, argv)
```
```text
int argc;
char *argv []?
{
```
```text
int pd [2];
char buffer [BUFSIZ];
```
```text
if (pipe(pd) == FAIL) {
fprintf (stderr, "pipe system call failed.\n");
exit (FAIL);
```
```text
}
```
```text
switch (fork()) {
```
```text
case -1: /* error */
fprintf (stderr, “fork system call failed.\n");
exit (FAIL);
```
```text
case 0: /* child process */
if (close () == FAIL) {
fprintf (stderr, “close pipe failed.\n");
exit (FAIL);
}
```
```text
if (dup (pd [0]) != 0) {
fprintf (stderr, “dup pipe failed.\n");
exit (FAIL);
```
```text
}
```
```text
if (close (pd [0]) == FAIL || close (pd [1]) == FAIL) {
fprintf (stderr, “dup pipe failed.\n");
exit (FAIL);
```
```text
}
```
```text
execl ("/bin/cat", “cat", NULL);
fprintf (stderr, “execl cat failed.\n");
exit (FAIL);
```
```text
default: /* parent process */
if (close (pd [0]) == FAIL) {
fprintf (stderr, "close pipe failed.\n");
exit (FAIL);
```
*— PDF-Seite 153 · Buchseite 143 —*
printf (“parent wrote: %s\\n", PM, sizeof(PM));
```text
if (write (pd[{1], PM, sizeof(PM)) == FAIL) {
fprintf (stderr, “pipe write filed\n");
exit (FAIL);
```
```text
}
```
```text
if (close (pd [1]) == FAIL) {
fprintf (stderr, “close pipe failed.\n");
```
```text
exit (FAIL);
}
/*
read (pd [0], buffer, BUFSIZ);
printf ("parent read: %s\n", buffer);
*/
}
exit (PARENT);
}
```
When compiled and run, this program writes the following to the standard output:
```text
parent wrote: Hi, kid
Hi, kid
```
This is similar to the example before, except that the cat command reads from its standard input. The parent process then uses the system call close() to close the pipe after writing. This sends an end-of-file character to the pipe and the standard input of the cat program, so that the program will terminate.
Two-Way Pipe In addition to sending data one way, we sometimes want to get replies. Two-way pipes make possible co-routines that exchange data. The following gives an example of how to implement a two-way pipe: /\* pipe2 - sends first argument thru pipe to child program, and reads the childs replay and sends it to standard-out. \*/
```text
#include
```
```text
/* program return status */
```
```text
#define OK 0
```
```text
#define FAIL -1
```
/\* fork return codes distinguished child from parent process \*/
```text
#define CHILD 0
#define PARENT 1
```
*— PDF-Seite 154 · Buchseite 144 —*
```text
/* pipe descriptor array elements */
#define READ 0
#define WRITE 1
```
```text
/* standard-io file descriptors */
#define STDINO
```
```text
#define STDOUT 1
```
```text
#define STDERR 2
```
/\* program for child to execl \*/
```text
#define PATH "“/usr/bin/bc"
```
```text
#define PROGRAM "be"
```
```text
/* standard-error handling macro */
```
```text
#define error(message) {fprintf (stderr,"%s: %s\n", argv [0], message);\
exit (FAIL); }
```
char buffer [BUFSIZ]; /\* buffer to read into \*/
```text
main (argc, argv)
```
```text
int argc;
char *argv [];
{
register char *p; /* pointer for scanning strings */
```
```text
int pepipe [2]; /* pipe from parent to child */
int cppipe [2]; /* pipe from child to parent */
```
```text
if (pipe (pcpipe) == FAIL || pipe (cppipe) == FAIL)
error("pipe system call failed.");
```
```text
switch (fork()) {
case FAIL: /* error */
error("fork system call failed");
```
```text
case CHILD: /* child process */
```
```text
/* close stdin to free for pipe connection */
if (close (STDIN) == FAIL)
error("close stdin failed");
```
```text
/* connect pipe to stdin of child */
if (dup (pepipe [READ]) != STDIN)
error("dup stdin pipe failed");
```
```text
/* close stdout to free for pipe connection */
if (close (STDOUT) == FAIL)
error("close stdout failed");
```
*— PDF-Seite 155 · Buchseite 145 —*
```text
/* connect pipe to stdout of child */
if (dup (cppipe [WRITE]) != STDOUT)
error("dup stdout pipe failed");
```
```text
/* close all pipes so child reads from stdin/out */
if (close (pcpipe [READ]) == FAIL ||
close (pcpipe [WRITE]) == FAIL | |
close (cppipe [READ]) == FAIL ||
close (cppipe [WRITE]) == FAIL )
error("close child pipes failed");
```
```text
/* execute basic calculator */
exec] (PATH, PROGRAM, NULL);
```
```text
/* if we get here, execl failed */
error("execl failed");
```
```text
default: /* parent process */
```
/\* close unused ends of the pipes \*/
```text
if (close (pcpipe [READ]) == FAIL ||
close (cppipe [WRITE]) == FAIL )
error("parent close pipe failed");
```
```text
/* write command line argument into pipe to child */
if (write (pcpipe [WRITE], argv [1], strlen(argv [1]))
== FAIL)
error("parent pipe write argv failed");
```
```text
/* be needs a newline to execute a line */
if (write (pcpipe [WRITE],"\n", 1) == FAIL)
error("parent pipe write nl failed");
```
```text
/* close pipe sends end-of-file to kill child */
if (close (pcpipe [WRITE]) == FAIL)
error("parent close pipe failed");
```
```text
/* read childs reply */
```
```text
if (read (cppipe [READ], buffer, sizeof (buffer) )
== FAIL)
error("parent pipe read failed");
```
/\* be sure string is terminated by NULL \*/
```text
for (p = buffer; *p != ‘\n'; ptt);
*p = NULL;
```
*— PDF-Seite 156 · Buchseite 146 —*
/\* output the answer \*/ puts (buffer); exit (OK); } } When this program is compiled and run with the command pipe2 ‘2+2' you'll see the following on the standard output: 4 Likewise, the command pipe2 ‘'scale=2 ; (100/3) \* 5° prints: 166.65 The be command is the COHERENT calculator program. It reads equations from the standard input and writes solutions to the standard output. Our Program reads an equation from its first command-line argument, and writess it through one pipe to a child process. The child process connects pipes to its standard input and standard output, then executes be. be reads the equation and sends the answer to the parent through the second pipe. The parent reads the second pipe and sends the solution to its standard output. This program is not very useful, but is a template. You can use this mechanism to give your C programs access to all of the COHERENT, /rdb, and other programs as if they were subroutines. This will save you a lot of programming. If a program exists to do what you want. use it. Programming Style
The program above also introduces a more advanced programming style. Most magic numbers have been defined to mnemonic constants to make the code easier to read and to simplify changes. A zero appearing in the code usually means nothing to the reader, but a name helps us understand what it is. In addition, if you have to change a magic number, it is much easier to edit it once at the top of the code than to search through all of the code to find it. It is especially difficult when the magic number is a common number like zero or one. You can not globally change such numbers, because they are used in many different ways. You must carefully search the code for the correct numbers to change.
Notice that the error condition is now handled by a simple macro called error(). It saves a lot of typing. makes the code easier to read, and standardizes the way errors are handled and reported.
Finally, every major section of code is commented. It takes a little more time, but saves a lot of time when we are debugging, changing, and maintaining the program.
*— PDF-Seite 157 · Buchseite 147 —*
## Fast Access
The final example shows a more practical program. This fastaccess program creates the search program and sends it a key through the first pipe. This child process finds a row in the inventory table and sends it back through the second pipe to the parent. In this example, the parent merely writes the retrieved row to the standard output, but you can modify the parent to do other things to the row.
```text
/*
```
```text
fastaccess - sends first argument thru pipe to child seek program,
and reads the childs offset replay, seeks the record,
reads it and sends the record to standard-out.
```
\*/
```text
#include
```
```text
/* program return status */
#define OK i)
#define FAIL -1
```
```text
/* fork return codes distinguished child from parent process */
#define CHILD 0
#define PARENT 1
```
```text
/* pipe descriptor array elements */
#define READ 0
#define WRITE 1
```
```text
/* standard-io file descriptors */
#define STDINO
```
```text
#define STDOUT 1
```
```text
#define STDERR 2
```
/\* program for child to execl \*/
```text
#define PATH “/usr/rdb/bin/search"
#define PROGRAM "search"
#define METHOD “=mb"
```
```text
#define TABLE “inventory”
```
```text
#define KEY “Item"
```
```text
/* standard-error handling macro */
#define error(message) {fprintf (stderr,"%s: %s\n", argv [0], message) ;\
exit (FAIL); }
```
char buffer [BUFSIZ]; /\* buffer to read into \*/
*— PDF-Seite 158 · Buchseite 148 —*
```text
main (argc, argv)
```
```text
int argc;
char *argv [];
```
```text
{
```
```text
register char *p; /* pointer for scanning strings */
pepipe [2]; /* pipe from parent to child */
eppipe [2]; /* pipe from child to parent */
```
```text
file; /* file descriptor for table file */
from, to; /* offsets of record in table */
xfrom, xto; /* offsets in secondary index file */
```
```text
int
int
int
int
int
```
```text
if (pipe (pcpipe) == FAIL || pipe (cppipe) == FAIL)
error("pipe system call failed.");
```
```text
switch (fork()) {
case FAIL: /* error */
error("fork system call failed");
```
```text
case CHILD: /* child process */
```
```text
/*
if
```
```text
/*
if
```
```text
/*
af
```
```text
/*
if
```
```text
/*
if
```
```text
/*
```
```text
close stdin to free for pipe connection */
(close (STDIN) == FAIL)
error("“close stdin failed");
```
```text
connect pipe to stdin of child */
(dup (pcpipe [READ]) I= STDIN)
error("dup stdin pipe failed");
```
```text
close stdout to free for pipe connection */
(close (STDOUT) == FAIL)
error("close stdout failed");
```
```text
connect pipe to stdout of child */
(dup (cppipe [WRITE]) != STDOUT)
error("dup stdout pipe failed");
```
```text
close all pipes so child reads from stdin/out */
(_ close (pepipe [READ]) == FAIL ||
close (pcpipe [WRITE]) == FAIL ||
close (cppipe [READ]) == FAIL | |
close (cppipe [WRITE]) == FAIL )
error("close child pipes failed");
```
```text
execute program */
```
execl (PATH, PROGRAM, METHOD, TABLE, KEY, NULL);
```text
/*
```
```text
if we get here, execl failed */
```
```text
error("execl failed");
```
*— PDF-Seite 159 · Buchseite 149 —*
```text
default: /* parent process */
/* close unused ends of the pipes */
if (close (pepipe [READ]) == FAIL ||
```
```text
close (cppipe [WRITE]) == FAIL )
error("parent close pipe failed");
```
```text
/* write command line argument into pipe to child */
if (write (pcpipe [WRITE], argv [1], strlen(argv [1]))
== FAIL)
error("parent pipe write argv failed");
```
```text
/* needs a newline to execute a line */
if (write (pcpipe [WRITE],"\n", 1) == FAIL)
error("parent pipe write nl failed");
```
```text
/* close pipe sends end-of-file to kill child */
if (close (pcpipe [WRITE]) == FAIL)
error("parent close pipe failed");
```
```text
/* read childs reply */
if (read (cppipe [READ], buffer, sizeof(buffer) )
== FAIL)
error("parent pipe read failed");
```
```text
/* output the answer */
puts (buffer);
```
```text
exit (OK);
```
```text
}
```
```text
After you compile this program, the command
fastaccess 2
```
prints the following on the standard output:
Item Amount Cost Value Description
2 100 5 500 test tubes
This is similar to the last example. But here, several arguments are given to the search program. These are defined with the #define preprocessor statements, but they could be passed from the command line arguments of the parent program or created within the program, or read from another file, a technique which is called table driven programming.
The best way to program is to write simple code that gets its parameters and data from data-base tables. Then the programs can be easily modified by simply editing the driving data tables, without having to reedit and recompile the source code. Users can modify these programs without calling back the programmer.
*— PDF-Seite 160 · Buchseite 150 —*
```text
/rdb and C
```
tabletostruct: Convert a Table to a C struct
A useful /rdb command is tabletostruct. It converts an /rdb table to a C-language struct type and initializes it to the values in the table. You can compile this struct into your C program and access any field. This makes possible table-driven code. You can use the data base to enter and update your tables, and recompile the program when you wish. This is the fastest access to tables, but requires compiling, and the inflexibility of not being able to change the programs internally compiled tables while the program is running.
Here we start with a simple table, convert it to struct, make it a header file, and compile it into a simple program that prints out each field.
```text
To begin, we create a table called table, which appears as follows:
A B c
```
```text
1 2 3
Now, we use tabletostruct to covert table to a struct:
tabletostruct Table table < table > table.h
The output is written into the header file table.h, which appears as follows:
```
```text
struct Table
```
```text
{
```
```text
char *A;
```
```text
char *B;
```
```text
char *C;
```
```text
} table [] =
{ "1","2","3" }
7
```
```text
The following program displays the structed contents of table.h:
#include “table.h"
```
```text
main ()
{
printf ("A=%s\n", table[0].A);
printf ("B=%s\n", table[0].B);
printf ("C=%s\n", table[0].c);
}
When compiled and run, the program prints the following onto the standard output:
```
```text
A=1
B=2
Cc=3
```
Note that the struct is an array and that we have to give a subscript for each row we want. We can also put the tabletostruct into the Makefile to further automate the re-compilation:
*— PDF-Seite 161 · Buchseite 151 —*
```text
printtable: table.h printtable.o
cc -o printtable printtable.o
```
```text
table.h: table
tabletostruct Table table < table > table.h
```
This says that the printable program depends upon table.h being up to date, and table.h depends upon table being up to date. If you modify table since the last compile, make will re-execute the tabletostruct command.
Our next example begins with a bigger table. called inventory. The command tabletostruct Inventory inventory \< inventory writes the following to the standard output:
```text
struct Inventory
```
```text
{
```
```text
char *Item;
```
```text
char *Amount;
```
```text
char *Cost;
```
```text
char *Value;
```
```text
char *Description;
```
```text
} inventory [] =
```
{ . 4"," 50"," 150","“rubber gloves" }
```text
ry | 100°," 5"," 500","“test tubes" }
```
```text
rf 5"," 80"," 400","clamps" }
```
```text
al 23"," 19"," 437","plates" }
```
```text
Pi 99"," 24"," 2376","cleaning cloth" }
Pe g9"," 147","13083","bunsen burners" }
ef 5"," 175"," 875","scales" }
```
7
```text
You can refer to the Description of the third item with this code:
printf ("Item Name = %s\n", inventory [2].Description) ;
```
Remember that tables in C start with element 0. You can convert the strings to integers with the function atoi():
```text
int item; /* current inventory item number */
int row; /* current row number starting from 0 */
```
```text
item = atoi (inventory [row].Item);
```
Read Table into Memory: getfile() and fsize()
To get tables from the data base at run time, you can read the table into memory and set up an array of pointers to reference any field by row and column number. Use the COHERENT system calls open() and stat() to get the size of the table, and the function malloc() to get that much memory. Then use read() to copy the whole table into memory and run throu
it with a loop that sets a two-dimentional array of pointers to point to every field in the array. Then you can reach any field with:
*— PDF-Seite 162 · Buchseite 152 —*
```text
char *field, *p_table [][];
int row, column;
```
```text
field = p_table [row][column];
```
To keep from having to hard code the size of your pointer table. first find out how many columns and rows you have by running through the memory counting newline characters. You might turn tabs and newlines into NULs while you go. Then malloc() enough memory to hold this array of pointers and run through the memory again to set the pointer array to pointing to fields.
Here are some routines that show examples of how to do this.
```text
/*
```
Copyright (c) 1990, 1991 Schaffer and Wright
getfile - reads a file into memory and returns pointer and size
\*/
```text
#include “rdb.h"
#include
#include
```
```text
char *filebuffer, *malloc();
int file, open(), read();
long fsize ();
```
```text
char *getfile (filename, p_size)
```
```text
char *filename;
unsigned *p_size;
{
```
```text
*p_size = 0;
```
```text
/* open the file */
if ((file = open (filename, 0)) < 0) {
fprintf (stderr, “Can’t open file %s.\n", filename);
fflush (stderr);
perror (“getfile");
return (NULL);
}
```
```text
/* get the memory to hold the table */
/* get size adding a byte for a trailing NUL */
*p_size = (unsigned) (fsize (file) + 1); /* byte for NUL end */
```
*— PDF-Seite 163 · Buchseite 153 —*
```text
}
```
```text
/* get a buffer in memory for the system */
if ((filebuffer = malloc ((unsigned) *p_size)) == NULL) {
fprintf (stderr,
“Can't malloc the size of file %s.\n", filename);
fflush (stderr);
perror (“getfile");
return (NULL);
¥
```
```text
/* read in the file and reset p_size to number of bytes read */
if ((*p_size = (unsigned) read (file, filebuffer, *p_size)) < 1) {
fprintf (stderr, “Can’t read file %s.\n", filename) ;
fflush (stderr) ;
perror ("getfile");
return (NULL);
}
```
```text
/* write NULL at the end of the buffer */
*(filebuffer + *p_size) = NULL;
```
```text
return (filebuffer) ;
```
getfile() calls fsize(), which gets the file size from the operating system via the system call
fstat():
```text
/*
```
```text
Copyright (c) 1990, 1991 Schaffer and Wright
fsize get the size of a file by calling the fstat routine
```
```text
*/
#include "rdb.h"
#include
#include
extern int Debug; /* global for debugging */
long fsize (file)
int file;
{
int fstat (); /* system call */
```
struct stat statusbuffer;/\* info on file \*/
*— PDF-Seite 164 · Buchseite 154 —*
```text
/* get status information including size */
if ((fstat (file, &statusbuffer)) < 0) {
fprintf (stderr,
“fsize: Can’t get the size of file d\n", file);
perror ("fsize");
return (FAIL);
}
```
```text
if (Debug)
fprintf (stderr, “fsize: file size=td\n",
statusbuffer.st_size);
```
```text
/* return size */
return ((long) statusbuffer.st_size);
```
```text
/rdb Functions: librdb.a
```
In the directory, $RDB/lib is the archive librdb.a, which contains all of the functions called by the /rdb programs. You can call them like any function if you link the archive into your program. For example, the command
```text
cc -o prog prog.c librdb.a
```
compiles program. prog.c into executable prog, and links the contents of archive librdb.a into the final executable.
If you. or your system administrator, moves the file to directory /usr/lib you only need to add -Irdb to you compile line:
```text
cc -o prog prog.c -lrdb
```
Colroutines
Another file in $RDB/lib is named Colroutines. “Col” stands for “column,” because the functions largely handle the columns of a table. Colroutines contains documentation on each of the C functions in librdb.a. It is the header of the source code for each routine. It shows the description, function name, arguments and argument types. It should be enough information to use the function, without being able to see the code.
```text
Display Example
The example display.c calls the /rdb functions:
static char Copyright []="Copyright (c) 1990, 1991 Schaffer and Wright";
```
```text
/*
```
```text
display will read a table or list file and send to standard-out
*/
```
#define USAGE “usage: display \< tableorlist\\n"
```text
#include “rdb.h"
```
*— PDF-Seite 165 · Buchseite 155 —*
```text
int Debug; /* global for debugging */
```
struct rowstruct row; /\* row information \*/
```text
int colgeth (), colgetr (); /* input functions */
int colputh (), colputr (); /* output functions */
int colinit (), coldump (); /* utility functions */
```
```text
main (argc, argv, envp)
int argc;
```
```text
char *argv [
char *envp [
```
```text
{
```
```text
l;
17
```
```text
register columns; /* columns returned */
register i; /* index for loops */
```
```text
/* handle command line arguments */
for (i = 1; i < argc; i++) {
if (argv [1][0] == ’-') {
switch (argv [1][1]) {
```
```text
case 'D’:
if (argv [1][2] != Eos) {
Debug = atoi (&(argv [1][2]));
} else {
Debug = TRUE;
}
break;
/* add other options here */
```
```text
default:
break;
}
} else {
```
```text
/* get non-option arguments, like files, here */
}
}
```
```text
/* get table or list headlines */
if ((columns = colgeth (&row)) == EOF)
exit (EOF);
```
```text
/* output headlines */
colputh (&row);
```
*— PDF-Seite 166 · Buchseite 156 —*
/\* read in each row till end-of-file \*/
```text
while ((columns = colgetr (&row)) I= EOF) {
/* output each row, or do other row processing */
colputr (&row);
```
```text
}
```
```text
/* return status code becomes shell $? variable for testing */
exit (OK);
}
```
Compile it with the command: cc display.o -o display librdb.a This assumes that lbrdb.a is in the current directory. If it is not, use its full path name. When invoked with the command display \< inventory display displays the following on the standard output: Item Amount Cost Value Description
```text
1 3 50 150 rubber gloves
2 100 5 500 test tubes
```
3 5 80 400 clamps
4 23 19 437 plates
```text
5 99 24 2376 cleaning cloth
6 89 147 13083 bunsen burners
7 5 175 875 scales
```
```text
Likewise, the command
display < maillist
displays the following on the standard output:
```
Number 1
```text
Name Ronald McDonald
Company McDonald’s
Street 123 Mac Attack
```
City Menphis
State TENN
ZIP 30000
Phone (111) 222-3333
*— PDF-Seite 167 · Buchseite 157 —*
Number 4
Name Chiquita Banana
Company United Brands
Street Uno Avenito De La Revolution
```text
city San Jose
State Costa Rica
ZIP 123456789
```
## Phone 1234
The first line is the copyright notice. It is declared to be a static char so that it will appear in the object module and the binary code.
The next comment is a description of the purpose of the program. The USAGE definition gives the syntax of the program. It can be displayed when a syntax error is detected. The debugging system is described in the next section.
The row structure is defined in the rdb.h header file that can be included in your programs. row contains lots of information about the headline and rows of the input table or list file. It is passed to the various col functions, which are declared below row.
After main(), the command line arguments are handled. Only the Debug variable is set, but this code can be edited to get all expected options and other arguments.
The col functions read in the headline and display it, followed by each row in the table or list.
The return command returns an exit status so that the program can be tested with the shells if, while, and for statements.
You can copy this program to start your own program. You can process each row of the table as it is read in by inserting your code within the while loop. Have fun, but remember, shell programming is much easier.
Debugging The Debug variable is an external global variable that can be seen by all of the functions.
The advantage of this method of debugging is that it is in the final product so that diagnostics can be run when errors are found by users and service people.
On the command line one can put -D to turn on debugging traces. These messages are printed out as the program runs to show the value of certain key variables. To control the quantity of output, one can follow the option with a number. The higher the number, the more output. -D9 turns on all output, which is a lot to wade through. but shows
everything.
In the example below, all diagnostics are dumped. Each function gives its name and the value of variables. colgeth( is the column-get-header function which calls colinit() to initialize the row buffers.
The COHERENT function malloc() is invoked to get memory for head and row data. This is part of the dynamic buffering that allows the programs to get as much memory as they can to handle large heads and rows. In this way the /rdb programs are not limited by software. but only by available hardware memory.
Because pointers are often a problem in C, several pointers are printed out. Their values don't mean much, but can be checked to see that they have been set to reasonable numbers. coldump lists all of the variables and their values in the row structure. You can
*— PDF-Seite 168 · Buchseite 158 —*
also call coldump() from your program if you wish. (Of course, you can use the COHERENT debugger db. if you prefer.)
colgetr() also displays the columns as they are read, so that you can see what it is seeing. All of this is coming to you through the standard error (aka stderr), so that you can redirect it. It is not buffered, so it comes out before the table which is coming through the buffered standard output. and is not sent until the buffer is full or the stream is closed on program termination.
```text
The command
display -D9 < inventory
prints the following to the standard error:
```
```text
colgeth: row=14976 filein=0
colinit: row=14976
colinit: bufsize=2048
colinit: colsize=2
colinit: p_buffer allocated
colinit: maxcolumns=1024
colinit: p_ heads allocated
colinit: p_ columns allocated
colinit: p_collengths allocated
coldump: ------------ aa aaa
```
```text
row pointer
row=14976
```
```text
file pointer for input file
row->p_filein=14754
```
```text
fileout pointer for input fileout
row->p_fileout=0
```
```text
points to buffer to write into
row->buf fer=16224
```
```text
points to (offset) buffer to write into
row->p_buffer=16224
```
```text
buffer size
row->bufsize=2048
```
```text
points to end of buffer
row->p_endbuffer=18272
```
```text
points to each head found in lists
row->p_heads=18274
```
```text
to number of head columns found
row->heads=0
```
```text
points to each column found
row->p_columns=20324
```
```text
number of columns
row->columns=0
```
```text
number of colsize
row->colsize=2
```
```text
number of maxcolumns
row->maxcolumns=1024
```
```text
each column’s length
row->collengths=22374
```
```text
entire row length
row->rowlength=0
```
```text
boolean fixed or variable
```
*— PDF-Seite 169 · Buchseite 159 —*
```text
row->fixed=0
boolean list or table
row->list=0
coldump: ---------------- een nn nnn <---
Item
Amount
Cost
Value
Description
colgetr: end-of-row.nrow->rowlength = 37
colgeth: row->heads=5
```
```text
colgetr: end-of-row.nrow->rowlength = 37
colgeth: row->columns=5 length=38 fixed=0 list=0
colputh: row->p_fileout=0
1
3
50
150
rubber gloves
colgetr: end-of-row.nrow->rowlength = 36
2
100
5
500
test tubes
colgetr: end-of-row.nrow->rowlength = 33
3
}
80
400
clamps
colgetr: end-of-row.nrow->rowlength = 29
4
23.
19
437
plates
colgetr: end-of-row.nrow->rowlength = 29
5
99
24
2376
cleaning cloth
colgetr: end-of-row.nrow->rowlength = 37
6
89
147
13083
bunsen burners
```
*— PDF-Seite 170 · Buchseite 160 —*
```text
/rdb and C
```
```text
colgetr: end-of-row.nrow->rowlength = 37
7
5
175
875
scales
colgetr: end-of-row.nrow->rowlength = 29
colgetr: eof
Item Amount Cost Value Description
```
```text
1 3 50 150 rubber gloves
2 100 5 500 test tubes
```
3 5 80 400 clamps
4 23 19 437 plates
```text
5 99 24 2376 cleaning cloth
6 89 147 13083 bunsen burners
7 5 175 875 scales
```
We did warn you that there was a lot of it.
## Fast-Access Example
The program inverted.c, found in directory $RDB/lib, demonstrates how to use the inverted method from within a C program:
```text
/* inverted.c is a sample program which illustrates the usage of the
fast access librdb.a routines (index and search).
specifically, this program exercises xinverted() and sinverted().
the search and index programs do essentially the same thing for
all fast access methods, and provide more command line options.
The following compile command assumes that the include file rdb.h and
library archive (distributed in the lib directory of rdb’s home dir)
are in the current directory: “cc -O inverted.c librdb.a -o xinverted"
Link the resulting xinverted binary to sinverted.nCall xinverted to
perform indexing and sinverted to perform searching.
```
&7/
char Copyright[] = "Copyright (c) 1990 by Schaffer and Wright";
```text
/*
```
```text
index index the given file according to the method specified.
It calls the xinverted (for index) routine.
```
```text
search search the given file using the method specified.
It calls the sinverted (for search) routine.
```
\*f,
#define USAGE “usage: %s [-n -x] tableorlist [keycolumn ...] [ \< keytable ]\\n"
*— PDF-Seite 171 · Buchseite 161 —*
```text
/*
```
-n = numeric comparison of key and column value
```text
-x = partial match and upper or lower case insensitive
*/
```
```text
#include “rdb.h"
int Debug; /* global for debugging */
char *Program; /* argv [0] program name */
```
char \*Function = "main"; /\* current function name \*/
/\* error message table(make into include and automatic error handling) \*/
```text
#define NOTABLE 1
#define EOPTION 2
#define NOMEM 3
#define NOFILENAME 4
#define NOFILE 5
#define NOPUT 6
#define NOKEYHEADS 7
```
```text
/* structures */
```
```text
struct rowstruct rowfile;
struct rowstruct rowkey;
struct keystruct key;
```
```text
/* functions called */
int sinverted ();
int xinverted ();
```
int (\*method) (); /\* method function pointer \*/
```text
/* comparison routines */
```
int colcmp (); /\* default: ignore blanks \*/
```text
int collook (); /* -x partial match, case insensitive */
int numemp (); /* =n numeric comparison */
```
int stremp (); /\* -x exact character match \*/
```text
/* flags */
```
int foldcase = FALSE; /\* -x sort fold upper and lower case \*/
```text
main (argc, argv, envp)
```
```text
int argc;
char *argv :
char *envp [];
```
```text
{
```
*— PDF-Seite 172 · Buchseite 162 —*
```text
register a; /* index for arguments */
```
```text
register xe /* row found index */
```
```text
char *p; /* character pointer */
```
```text
int rows=0; /* number of rows matched */
int search=FALSE; /* search or index */
```
```text
int matches; /* columns matched */
```
```text
FILE *fopen (); /* functions used */
char *rindex();
```
```text
/* get arguments */
if (Debug) fprintf (stderr, “argc=td\n", argc);
if (arge < 2) {
fprintf (stderr, USAGE, argv [0]);
exit (NOTABLE) ;
}
```
```text
/* initialize key structure */
```
```text
if (keyinit (&key) == FAIL)
exit (NOMEM) ;
```
```text
key.singlerow = FALSE;
```
```text
/* initialize rowkey structure */
if (colinit (&rowkey) == FAIL)
exit (NOMEM) ;
```
/\* initialize: called by search or index \*/
```text
/* handle path names, walk to end looking for slash */
if (p = rindex(argv[0], '/’)) ++p;
```
```text
else p = argv[0];
```
/\* if the command name begins with ’s’ assume search procedures \*/
```text
if (*p == ‘'s‘)
search = TRUE; /* search */
else search = FALSE; /* index */
```
```text
if (search)
method = sinverted;
else method = xinverted;
```
```text
/* default comparison method is ignore blanks */
key.compare = colcmp;
```
```text
/* loop through arguments looking for flags and file name */
for (a = 1; a < argc; att) {
if (Debug)
fprintf (stderr, "argv [%d]=%s\n", a, argv [a]);
```
*— PDF-Seite 173 · Buchseite 163 —*
```text
if (argv [aJ[0] == ‘-') {
switch (argv [a][1]) {
```
```text
case ‘D’':
if (isdigit(argv [a][2]))
Debug = atoi (&argv [a][2]);
else Debug = TRUE;
```
```text
break;
```
```text
case ‘n’:
key.compare = numcmp;
break;
```
```text
case ‘x’:
```
```text
foldcase = TRUE;
key.compare = collook;
break;
```
```text
default:
fprintf (stderr,
“$s: $s option not recognized\n",
argv [0], argv [a]);
fprintf (stderr, USAGE, argv [0]);
exit (EOPTION) ;
```
```text
}
```
```text
} else {
if (key.p_ filename == NULL) {
key.p_ filename = argv [a];
} else {
rowkey.p_heads [rowkey.heads++] = argv [a];
```
```text
}
```
```text
/* do we have a file to open */
if (key.p_filename == NULL) {
```
```text
fprintf (stderr, “ts: no file name\n", argv [0]);
fprintf (stderr, USAGE, argv [0]);
exit (NOFILENAME) ;
```
```text
/* open the file */
key.file = rowfile.p filein = fopen (key.p filename, READ);
```
```text
rowfile.p fileout = stdout;
```
*— PDF-Seite 174 · Buchseite 164 —*
```text
if (rowfile.p filein == NULL) {
fprintf (stderr,
"$s: Can not open %s\n", argv [0], key.p_ filename) ;
```
```text
exit (NOFILE);
```
```text
if (Debug)
fprintf (stderr, "%s: rowfile.columns=%d\n",
argv [0], rowfile.columns) ;
```
```text
/* get the head line of the file */
if ((rowfile.columns = colgeth (&rowfile)) == EOF)
exit (EOF);
```
```text
if (Debug)
fprintf (stderr, “ts: rowfile.columns=%d\n",
argv [0], rowfile.columns) ;
```
```text
/* put the head line of the file */
if (search) {
if (colputh (&rowfile) == FAIL)
exit (NOPUT);
}
```
```text
/* if the key columns are not in the command line,
get from the stdin */
```
```text
rowkey.p filein = stdin;
```
```text
rowkey.p fileout = stdout;
```
```text
if (rowkey.heads == 0) {
/* get from key head */
if ((rowkey.heads = colgeth (&rowkey)) == EOF)
exit (EOF);
```
```text
}
```
```text
/* get first row if list */
if (rowfile.list)
if ((rowfile.columns = colgetr (&rowfile)) == EOF)
exit (EOF);
```
```text
if (rowkey.list)
if ((rowkey.columns = colgetr (&rowkey)) == EOF)
exit (EOF);
```
*— PDF-Seite 175 · Buchseite 165 —*
```text
/* find key columns in the file columns */
matches = colmatch (rowfile.p heads, rowfile.heads,
rowkey.p_ heads, rowkey.heads, key.keytocolumn) ;
```
```text
if (matches != rowkey.heads) {
fprintf (stderr,
"%s: Can not find your keys in column heads.\n",
argv [0]);
```
```text
exit (NOKEYHEADS) ;
}
```
```text
/* if index, go and index and then exit */
if (1! search) {
if (Debug) fprintf (stderr,
“ts: rowfile.p filein=%d\n", argv [0], rowfile.p filein) ;
```
```text
/* call method */
if ((rows = (*method) (&key, &rowfile, &rowkey)) < 0) {
perror (argv [0]);
exit (rows);
}
exit (OK);
}
```
```text
/* get first row of keys if table */
if (Debug) {
fprintf (stderr, "ts: before colgetr (&rowkey)\n",
argv [0]);
colputh (&rowkey) ;
}
```
```text
if (rowkey.list == FALSE)
if ((rowkey.columns = colgetr (&rowkey)) == EOF)
exit (NOKEYHEADS) ;
```
```text
if (Debug) {
fprintf (stderr,
“$s: after colgetr (&rowkey)\n", argv [0]);
colputh (&rowkey) ;
colputr (&rowkey);
```
*— PDF-Seite 176 · Buchseite 166 —*
/\* loop getting key(s) from stdin \*/
```text
do {
if (Debug) {
fprintf (stderr,
“$s: Before method rowkey.columns=%d\n",
argv[0], rowkey.columns) ;
}
/* don’t look if no keys */
if (rowkey.columns == 0)
continue;
/* call method */
rows = (*method) (&key, &rowfile, &rowkey) ;
if (Debug) fprintf (stderr,
“@st After method rows=%d key.rowoffsets [0]=%d\n",
argv[0], rows, key.rowoffsets [0]);
if (rows <= 0) {
continue;
}
for (xr = 0; r < rows; r++) {
if (fseek (rowfile.p filein,
key.rowoffsets [r], BEGINNING)
== BADSEEK)
fprintf (stderr, “search: Bad seek.\n");
colgetr (&rowfile);
colputr (&rowfile);
}
}
```
while ((rowkey.columns = colgetr (&rowkey)) != EOF);
```text
exit (OK);
```
*— PDF-Seite 177 · Buchseite 167 —*
# Section 17 — Manual Pages
The following gives manual pages for all /rdb commands. These include the commands used by the /act accounting system, which is included as an example of /rdb programming.
*— PDF-Seite 178 · Buchseite 168 —*
*— PDF-Seite 179 · Buchseite 169 —*
A
accounting terms — Definition The following defines several of the more commonly used accounting terms. These are included to help you understand the descriptions of /rdb's accounting package.
Financial information that records the day-to-day operation of a business is recorded in an account. A simple account is made up of three parts:
1. A title that describes the name of the information being stored in the account;
2. The left side of the account, used to record a debit; and
3. The right side of the account, used to record a credit.
This simple configuration is referred to as a ‘T’ account because its shape resembles a capital T:
Title
```text
Debit | Credit
```
A ledger is the combination of all the accounts maintained by a business. Transactions are posted to accounts through a journal entry, as in the following example:
```text
Cash | 500.00 |
Sales | | 500.00
```
Entries recorded on the far left are debits; entries indented from the left are credits. Accounts fall into the following classifications: Assets Anything that is owned and has a monetary value.
```text
Liabilities
Amounts owed to others.
```
Capital This is the owner's equity in the business. It is equal to the total assets minus the total liabilities.
```text
Revenue
Proceeds obtained in the course of doing business.
```
```text
Expenses
Costs incurred in the course of doing business.
```
Further information on accounting terms may be obtained from any textbook on accounting principles. Your local public library should contain several examples.
```text
See Also
act
```
Notes
Please note that /rdb's accounting system is meant to serve as an example of data-base programming with /rdb. It is not designed to be an exhaustive accounting package. nor is it designed to teach you how to perform accounting. Mark Williams technical support will help you if you have a problem with an /rdb command, but not with problems that involve the principles of accounting. Caveat utilitor.
*— PDF-Seite 180 · Buchseite 170 —*
```text
act — /rdb Command
List all /act commands
act
```
/rdb comes with a set of commands that implement a basic accounting system, suitable for running a small business. These commands, called /act commands, are kept in directory SRDB/act.
```text
The accounting system consists of the following sub-systems:
gl General ledger
```
```text
inv Inventory
```
```text
opr Operations, for manufacturing
```
```text
pay Payroll
```
```text
pur Accounts payable and purchasing
```
```text
sales
Accounts payable and sales
```
The command act lists all /act commands.
```text
Example
Typing act displaying the following on your screen:
```
```text
act close income postap shorttoaccount
adjust consolidate invoice postar start
```
balance cstate makecatalog postpay tax.calc
```text
bom fillform onhand purchase trial
calculate foot po sale vstate
chartdup getjournal post ship w2
```
Many act commands have their own entries in this manual.
See Also
```text
accounting terms
```
Notes
Please note that /rdb’s accounting system is meant to serve as an example of data-base programming with /rdb. It is not designed to be an exhaustive accounting package, nor is it designed to teach you how to perform accounting. Mark Williams technical support will help you if you have a problem with an /rdb command, but not with problems that involve the principles of accounting. Caveat utilitor.
```text
addcol — /rdb Command
```
```text
Add a column to a table
addcol newcolumn < table
```
The command addcol appends one or more new columns to table. The column is initialized to blank spaces, and is given the name newcolumn.
Example
The command
*— PDF-Seite 181 · Buchseite 171 —*
```text
addcol New < inventory
```
modifies table inventory to appear as follows:
Item Amount Cost Value Description New
1 3 50 150 rubber gloves
2 100 5 500 test tubes
3 5 80 400 clamps
4 23 19 437 plates
5 99 24 2376 cleaning cloth
6 89 147 13083 bunsen burners
7 5 175 875 scales
Note that column New has been added to the table.
```text
See Also
jointable, number
```
```text
adjust — /act/gl Command
Create adjusted trial balance table
adjust
```
The command adjust is part of the accounting/ general ledger system that is included with /rdb. It produces the adjusted trial balance sheet, called adjusttrial, by adding the trialbalance table trialbalance with the journal-of-adjustments table journaladjust.
The accountant makes adjustments at the end of the accounting period, to reflect changes in inventory, depreciation, depletion, amortization, and so on. These are computed costs of doing business that are assigned to each accounting period.
Example
The following gives an example of table trialbalance:
Account Debit Credit Format Taxline Short Name
1010 11178 B-A 4L01 cash Cash
3010 13500 I-I 10la sales Sales
```text
3080 250 I-I 106 royalty Gross royalties
3100 3286 I-I 108 income Other Income
4020 3601 I-COGS 102-A2 merch Misc Merchandise
4030 2100 I-cOGS 102-A3 wages Salary and Wages
4370 2 I-E 122 parking Business parking
4380 41 I-E 122 travel Business travel
4384 114 I-E 122 hotel Business hotel
```
The following gives an example of table journaladjust:
*— PDF-Seite 182 · Buchseite 172 —*
Account Debit
```text
1310
1330
1420
4010 20000
4080
4170 i)
4180 0
4215 0
```
Credit
Format Taxline Name
```text
B-A
B-A
B-A
I-coGs
I-coGs
I-E
I-E
I-E
```
```text
4L12a
102-Al
102-A4
121
118
122
```
```text
Beginning Inventory
Ending Inventory
Accum Depreciation
Accum Depletion
Accum Amortization
Beginning Inventory
Ending Inventory
Depreciation
Depletion
Amortization
```
The command adjust then produces the table adjustedtrial by combining trialbalance with journaladjust. In this example, adjustedtrial appears as follows:
Account Debit
```text
1110 2130
1310 0
1330 0
1420 t)
3010
```
3080
3100
```text
4010 20000
4020 3601
4030 2100
4080
```
```text
4170 0
4180 to}
4215 ()
4370 2
4380 41
4384 114
See Also
```
```text
act, balance
```
```text
append — /rdb Command
```
Credit
```text
13500
250
3286
```
22130
Format Taxline Short
```text
Add a row to a table and update index tables
append [-h -m[bhirs]] table [keycolumn ...] < tableorrow
```
```text
inv
adeprec
adeplet
aamort
sales
royalty
income
beginv
merch
wages
endinv
deprec
deplet
amor
parking
travel
hotel
```
Cash
Inventory
```text
Accum Depreciation
Accum Depletion
Accum Amortization
Sales
```
```text
Gross royalties
Other Income
```
```text
Begin Inventory
Misc Merchandise
Salary and Wages
Ending Inventory
Depreciation
Depletion
Amortization
Business parking
Business travel
Business hotel
```
The command append appends the row in table tableorrow onto the end of table. It also updates the appropriate index table so that the next search will find it. For the record method of indexing, append adds the new record's offset to the end of the index table. For the inverted method of indexing, it adds the record and then sorts the table.
*— PDF-Seite 183 · Buchseite 173 —*
Options
append recognizes the following options:
-h tableorrow has no /rdb head line and dash line. This option is useful when you only have a row to append to a table, but it does not have a head line.
```text
-m{bhirs]
Use a fast-access method. See the manual page for search for a description of the
fast-access methods and how to invoke them.
```
```text
Example
Consider the table inventory, which is defined as follows:
```
```text
Item Amount Cost Value Description
1 3 50 150 rubber gloves
2 100 5 500 test tubes
3 5 80 400 clamps
4 23 19 437 plates
5 99 24 2376 cleaning cloth
6 89 147 13083 bunsen burners
7 5 175 875 scales
```
This table has an index table, called record, which appears as follows: Offset
```text
76
113
147
177
207
245
283
```
```text
Finally, consider the table newrecord, which is as follows:
Item Amount Cost Value Description
```
8 35 105 0 pipettes
```text
Note that newrecord has the same columnar layout as inventory.
The following command appends newrecord onto the end of inventory:
append -mr inventory < newrecord
```
After append has done its work, inventory appears as follows:
*— PDF-Seite 184 · Buchseite 174 —*
```text
ascii
```
Item Amount
```text
99
89
```
```text
5
35
```
DIAKDUPWNHHR
inventory’s index table now appears as follows:
```text
Offset
76
```
```text
113
147
177
207
245
283
313
```
The new “313” entry in the secondary index table inventory.r is the offset to record 8 —
```text
a9
24
147
175
105
```
```text
2376
13083
875
```
```text
i)
```
```text
Description
rubber gloves
test tubes
clamps
```
```text
plates
cleaning cloth
bunsen burners
scales
pipettes
```
that is, the number of bytes for the beginning of the file to record 8.
See Also
```text
delete, index, replace, search
```
```text
ascii — /rdb Command
Return the ASCII value of a character
```
ascii character...
The command ascii converts each of the characters in its first argument to a spacedelimited series of numbers. You can use this command to find the internal computer representation of a character. Any strings following the first are ignored. If you have spaces
in your string, be sure to put quotation marks around them.
Example
```text
The command
ascii aAl
produces:
97 65 49
The command
ascii’ '
produces:
32
```
*— PDF-Seite 185 · Buchseite 175 —*
Note that the single space character, enclosed within apostrophes, is converted to its ASCII code in decimal (32).
See Also
```text
chr
COHERENT Lexicon: ASCII
```
*— PDF-Seite 186 · Buchseite 176 —*
backup — Technical Information When you are using /rdb to store and manipulate your data, you must back up your data regularly. If you do not back up your data and your disk should fail for whatever reason. your data will be irretrievably lost.
See the COHERENT manual section 2, Using the COHERENT System, for a detailed description of how to back up your data. Also see the Lexicon articles on ustar and cpio for descriptions of how to use these tools to back up your data.
```text
balance — /act/gl Command
Create balance sheet from adjusted trial balance
balance
```
The command balance is part of the accounting/general-ledger system included with /rdb. It reads table adjustedtrial and writes a balance sheet into table and writes it into file
balancesheet.
Example
Consider the table adjustedtrial, as follows:
Account Debit Credit Format Taxline Short Name
1010 11178 B-A 4L01 cash Cash
1110 2130 B-A 4L06 inv Inventory
```text
1310 0 B-A 4L09a adeprec Accum Depreciation
1330 0 B-A 4L10a adeplet Accum Depletion
1420 0 B-A 4L12a aamort Accum Amortization
3010 13500 I-I 10la sales Sales
```
```text
3080 250 I-1 106 royalty Gross royalties
3100 3286 I-I 108 income Other Income
4010 20000 I-COGS 102-Al beginv Begin Inventory
4020 3601 I-cOGS 102-A2 merch Misc Merchandise
4030 2100 I-COGS 102-A3 wages Salary and Wages
4080 22130 I-COGS 102-A4 endinv Ending Inventory
4170 0 I-E 121 deprec Depreciation
4180 0 I-E 118 deplet Depletion
```
```text
4215 i) I-E 122 amor Amortization
4370 2 I-E 122 parking Business parking
4380 41 I-E 122 travel Business travel
4384 114 I-E 122 hotel Business hotel
```
The command balance writes the balance sheet into balancesheet, which appears as follows:
```text
Makeapile, Inc.
31 December 1985
Balancesheet
```
*— PDF-Seite 187 · Buchseite 177 —*
11178 Cash
```text
2130 Inventory
t) Accumulated Depreciation
te) Accumulated Depletion
i) Accumulated Amortization
```
13308 Total Assets
13308 Retained Earnings (Profit)
13308 Total Liabilities and Equity
See Also
```text
act, adjust
```
```text
blank — /rdb Command
```
```text
Replace all data in a record with spaces
blank < tableorlist
```
The command blank replaces with spaces every values in each record of tableorlist.
The command update uses blank when it updates a record. update temporarily replaces the record it is updating with a blank record. This blank record serves as a record lock; this ensures that other users cannot read or update the record while it is being updated, but it leaves the rest of the table available for use.
Please note that when you pull up a blank record, it means that that record is being updated by someone else. Come back to it later.
Example To blank out the data fields in table maillist and then see the result. you could type the following:
```text
blank < maillist | see
This command produces the following output:
```
*— PDF-Seite 188 · Buchseite 178 —*
```text
Number“I $
```
```text
Name“*I $
Company “*I $
Street *I $
city*I $
```
```text
State*I $
```
```text
ZIP*I $
```
```text
Phone*I $
$
```
```text
Number“I $
```
```text
Name*I $
Company*I $
Street *I $
City*I $
```
```text
State*I $
ZIP*I $
```
```text
Phone*I $
```
Note the spaces between the tab (\*I) and the dollar sign ‘8’ that indicates the end of the line. The spaces replaced the characters, including spaces, that were in the original records.
Note too that the column names are untouched, so that this is a perfectly correct file as far as the /rdb commands are concerned. it just contains no data.
See Also
```text
see, update
```
```text
bom — /act/opr Command
Produce bill-of-materials from parts list
bom
```
The command bom is part of the accounting/operations system included with /rdb. It creates a bill-of-materials table from table part, which holds all of the items that are required to make a product, and the table saleitem, which holds all sales items from the sales department. This tells how many items must be manufactured or purchased to meet current sales orders.
bom writes its output into table bom.
```text
Example
Assume the table saleitem contains the following data:
```
Order Number Code Backord Qty Price Total Name
```text
1 1 rdb 10 1 1500 1500.00 /rdb
2 1 rdb 10 2 1500 3000.00 /rdb
3 1 rdb 10 5 1500 7500.00 /rdb
3 2 act 10 10 1500 15000.00 /act
4 1 rdb 10 5 1500 7500.00 /rdb
4 2 rdb 10 19 1500 28500.00 /rdb
5 Fs rdb 10 5 1500 7500.00 /rdb
5 2 act 10 9 1500 13500.00 /act
```
*— PDF-Seite 189 · Buchseite 179 —*
```text
Assume, too, that the table part contains the following data:
Code Subpart Count
```
```text
act binder 2
act actdoc 2
act f1 10
rdb binder 2
rdb rdbdoc 2
rdb fl 10
```
Code Qty
```text
actdoc 38
binder 112
fl 560
rdbdoc 74
```
You can see that we have orders for 19 copies of acts in the salesitem table. Each package has two documents, for a total of 38 actdocs. Note that table bom lists 560 floppies ((19 act x 10) + (37 rdb x 10)). We can order these, regardless oi which software packages are being put onto them.
See Also
```text
act
```
*— PDF-Seite 190 · Buchseite 180 —*
```text
calcpay — /act/pay Command
```
```text
Post payroll to ledgerpay
calcpay
```
The command calcpay is part of the accounting/ payroll system that is included with /rdb. It posts the payroll-journal table Journalpay to the payroll-ledger table ledgerpay. This ledger groups the pay checks by employee, and is used to create the W2 form.
Example
Assume that table journalpay has the following data:
Date Number Hours Salary Rate Gross Federal State Net
```text
860518 1 80 1000 0 1000 70 10 920
860518 2 80 ) 10 800 42 6 752
860518 3 30 0 10 300 0 0 300
```
Typing calcpay copies it to table calcpay.
```text
See Also
act, getjournal
```
```text
calculate — /act/gl Command
```
```text
Compute each tax form listed
calculate taxform...
```
The command calculate is part of the accounting/general-ledger system that is included with /rdb. It is a simple shell script that calculates each tax form listed on its command line.
Example
```text
The following command calculates the IRS 1040 form
calculate 1040
```
See Also
```text
act, filiform
```
Notes
Please note that the tax tables included with /rdb are from 1987. They are included solely to serve as examples, and no claim is made as to their accuracy when calculating current taxes. Caveat utilitor.
```text
cap — /rdb Command
Convert first letter of each word to upper case
cap < textfile
```
The command cap capitalizes the first letter of each word in textfile. It writes its results to the standard output.
```text
Example
Assume that table Inventory has the following data:
```
*— PDF-Seite 191 · Buchseite 181 —*
Item Amount Cost Value Description
```text
1 =} 50 150 rubber gloves
2 100 5 500 test tubes
```
3 5 80 400 clamps
4 23 19 437 plates
```text
5 99 24 2376 cleaning cloth
6 89 147 13083 bunsen burners
7 5 175 875 scales
```
As you can see, the column Descriptions has consists of words all in lower case. To capitalize the first letter of each word in Inventory file, type:
```text
cap < Inventory
```
This writes the following on the screen:
```text
Item Amount Cost ValueDescription
1 3 50 150 Rubber Gloves
2 100 5 500Test Tubes
3 5 80 400Clamps
4 23 19 437 Plates
5 99 24 2376Cleaning Cloth
6 89 147 13083Bunsen Burners
7: 5 175 875 Scales
```
See Also
```text
lowercase, uppercase
```
```text
cashflow — /rdb Command
Compute balance column of cash table
cashflow < cashtable
```
The command cashflow helps you manage your cash flow. It reads cashtable, which you design, then computes a running balance in a Balance column (which must be column 3) from an Amount column (which must be column 2).
Cash-flow analysis lets you see if you will always have enough money in hand to cover each day's bills. It makes cash management possible by telling you whether to put off an expense until a check arrives, ask for an advance, get to work and make more money, or
```text
control your spending.
Example
```
The following gives an example cashtable, called cash:
*— PDF-Seite 192 · Buchseite 182 —*
```text
cashflow
```
```text
Date Amount Balance Description
890101 512 current balance
890101 -450 rent check
890101 1000 pay check
890115 -300 estimated tax payment
890115 1000 pay check
890115 -1000 living expenses
890120 -900 big purchase
890201 1000 pay check
890201 -450 rent check
890215 1000 pay check
890115 -1000 living expenses
```
The command cashflow needs two columns, named Amount and Balance. (If you use different column names, you must edit the cashflow shell script). All other columns are optional. Each row in your table represents a projected income item (positive) or a projected expense (negative). This is your flow of cash. To summarize the cash flow in our example table cash, type:
```text
cashflow < cash
```
This prints the following on your screen:
```text
Date Amount Balance Description
890101 512 512 current balance
890101 -450 62 rent check
890101 1000 1062 pay check
890115 -300 762 estimated tax payment
890115 1000 1762 pay check
890115 -1000 762 living expenses
890120 -900 -138 big purchase
890201 1000 862 pay check
890201 -450 412 rent check
890215 1000 1412 pay check
890115 -1000 412 living expenses
```
That big purchase gives us a negative balance in 890120. Now that you know, you can do something about it. One move is to put the big purchase off until the first of February. After you edit table cash to reflect this change. it appears as follows:
*— PDF-Seite 193 · Buchseite 183 —*
```text
Date Amount Balance Description
890101 512 current balance
890101 -450 rent check
890101 1000 pay check
890115 -300 estimated tax payment
890115 1000 pay check
890115 -1000 living expenses
890201 1000 pay check
890201 -900 big purchase
890201 -450 rent check
890215 1000 pay check
890115 -1000 living expenses
```
Running cashflow again will tell us if this strategy works:
```text
Date Amount Balance Description
890101 512 512 current balance
890101 -450 62 rent check
890101 1000 1062 pay check
890115 -300 762 estimated tax payment
890115 1000 1762 pay check
890115 -1000 762 living expenses
890201 1000 1762. ~—-pay check
890201 -900 862 big purchase
890201 -450 412 rent check
890215 1000 1412 pay check
890115 -1000 412 living expenses
```
As you can see, this works — there's no negative cash flow for any period. You can also try other options.
You can do all of the inputting and editing in the text editor. You can execute commands in vi by using the exclamation ‘!’ shell feature; or from MicroEMACS by typing \!. You also might want to write out to a tmp file and use mv to overwrite your cash table so that it is file is up to date. For example, in vi you can type:
:!cashflow \< cashtable \> tmp ; mv tmp cashtable
sel The first line computes the Balance column, writes the result into a tmp file, and moves tmp to be the new cashtable. All of this is necessary because in COHERENT you cannot have one file as both input and output without wiping out the file. The second line, :e! pulls the new file into the vi editor and displays it on your screen. See Also COHERENT Lexicon: ksh, me, sh, vi
*— PDF-Seite 194 · Buchseite 184 —*
```text
chartdup — /act/gl Command
```
Check for duplicate names and accounts in chart
```text
chartdup
```
The command chartdup is part of the accounting/general-ledger system that is included with /rdb. It checks to see if there are any duplicates among the account numbers or the short names within the chart of accounts. This is the most common error that people make
when they update the chart of accounts.
Example
The following gives example output of chartdup:
Duplicate Account numbers in chart.
```text
4150 I-E 115 taxes
4150 I-E BE BS taxes
Duplicate Short names in chart.
4150 I-E 115 taxes
4150 I-E 115 taxes
```
```text
check.rdb — /rdb Command
```
```text
See chart.Account
Taxes
```
Taxes
See chart.Short
Taxes
Taxes
Report any rows in which columns do not match head line
```text
check.rdb < tableorlist
```
The command check.rdb counts the columns (number of tabs plus one) in the head line of an /rdb table or list formatted file. Then it displays information on each row that does not match the number of columns in the first head-line row. You should use it to see if your data entry is correct. If your head-line row is incorrect, then all of your rows will be
reported as errors.
check.rdb returns zero when all is correct, and nonzero when it has found an error. You can use this status value ($?) in a shell script to take different actions, depending upon the
validity of the table or list file.
```text
Examples
Here is a bad table, called badtable:
```
```text
Date Account Debit Credit
820102 101 25000
820102 211.1 25000
820103 150.1 10000
820103 101 5000
820103 211.2 5000
820104 130 30000
820104 201.1 15000
820104 101 15000
```
It is hard to see anything wrong with it.
```text
check.rdb < badtable
```
we see the following output:
Description
```text
cash from loan
```
```text
loan #378-14 Bank Amerigold
test equipment from Zarkoff
cash payment
```
```text
note payable to Zarkoff
inventory - parts from CCPSC
accounts payable to CCPSC
```
```text
cash payment to CCPSC for parts
```
However, when we run the command
*— PDF-Seite 195 · Buchseite 185 —*
check.rdb: Columns (4) do not equal headline columns (5) in row 3 (line 5). 820103 150.1 10000 test equipment from Zarkoff
```text
The command
see < badtable
gives us the following output:
```
```text
Date*IAccount *IDebit *ICredit *IDescription$
```
```text
----*I ------ “I----- “I ------ *----------- $
820102*1101*125000*I*Icash from loan$
820102*1211.1*1I*125000*Iloan number #378-14 Bank Amerigold$
820103*1I150.1 10000*I*Itest equipment from Zarkoff$
820103*1101*I*1I5000*Icash payment$
820103*I211.2*1I*1I5000*Inote payable to Zarkoff Equipment$
820104*1I130*1I30000*I*Iinventory - parts from CCPSC$
820104*1201.1*I*115000*Iaccounts payable to CCPSC*I$
820104*I101*I15000*I*Icash payment to CCPSC for parts$
```
Note that a tab is missing from row 3 (line 5) of badtable, between values 150.1 and 10000. The spaces hide the fact that it is missing.
When you work with a large file, run check.rdb first. It will find the tab problems and give you the information you need to find them. Then use a text editor to correct the problem.
You can move down to the first bad line by typing the following vi command :5. This takes you to line 5. Then to see the line, type the list command I:. (This is the letter el, not the number one). Or to do it in one step (move and list), type :51. Or you can using the following colon command to set all of the lines in the file to display tabs:
```text
rset list
To return it to normal display, use the command:
rset nolist
```
Edit in whatever changes you need, then go to the next bad line. You can change a space to a tab with the following command:
```text
ts/ /*I/
```
where the “I is the key on your keyboard that produces a tab. If you want to list three lines above and below the bad line. type:
2-3,4+31
If you use ve to enter your data, you will have fewer problems like this. Data from foreign sources should be checked carefully before you use it with /rdb.
```text
See Also
see, ve
COHERENT Lexicon: elvis, me, vi
```
Notes
This command is named check.rdb rather than check, as in other implementations of /rdb, to avoid clashing with the COHERENT command check, which does something very different.
*— PDF-Seite 196 · Buchseite 186 —*
```text
chr — /rdb Command
Display the character corresponding to a number
chr number ...
```
chr converts each of the integers on its command line to its corresponding ASCII character. You can use it to send special characters to the screen. This gives you a good way to produce special characters that are hard to type or are interpreted by the shell.
```text
Example
Here we convert several characters.
```
```text
chr 97 65 49
aAl
```
```text
chr 7
[beep]
```
```text
echo ‘chr 7‘Wake up
[beep]Wake up
```
The [beep] is the sound. It does not print on your terminal.
See Also
```text
ascii
COHERENT Lexicon: ASCII
```
```text
Clear.rdb — /rdb Command
Clear the terminal's screen
clear.rdb
```
The command clear.rdb clears your terminal screen of all characters and leaves the cursor in the upper left corner. It is useful for menus and forms that look better on a clear screen.
clear.rdb uses the termcap file of terminal capabilities to find the string of special characters that are needed to clear your screen. To work correctly, the TERM environmental variable must be set correctly to the name of your terminal as listed in /etc/termcap.
The COHERENT command clear.rdb also clears the screen.
```text
The /rdb command termput can also clear the screen, as follows:
termput cl
```
Speed
clear.rdb is quite fast, but there is a much faster way. Set a shell variable CLEAR to the output of the command clear.rdb like this:
```text
export CLEAR=‘clear’
Then you can use:
echo “$CLEAR"
```
in your shell programs for a fast clear. Put it into your .profile so that it will always be available. Use quotation marks around the shell variables in case they have special characters in them.
*— PDF-Seite 197 · Buchseite 187 —*
See Also
```text
termput
```
COHERENT Lexicon: clear, export, .profile, sh, TERM, termcap
Notes
This command is named clear.rdb rather than clear, as in other implementations of /rdb, to avoid clashing with the COHERENT command clear.
```text
close — /act/gl Command
```
Close accounting period creating journal for next
```text
close
```
The command close is part of the accounting/general-ledger system that is included with /rdb. It closes an accounting period, such as a month, quarter, or year, and creates the next period's journal, the table journalnext. When you start the next period, carry the journalnext forward by mving it to file journallast.
Example
The command close creates a file whose output resembles the following: Credit Ref
Account Date
```text
1010 850101
1110 850101
1310 850101
1330 850101
1420 850101
4997 850101
```
```text
column — /rdb Command
```
```text
display columns of a table in any order
```
```text
Debit
11178
22130
0
0
0
```
33308
```text
column [ Column... ] < tableorlist
```
```text
jl
```
Description
```text
brought
brought
brought
brought
brought
brought
```
```text
forward
forward
forward
forward
forward
forward
```
The command column reads tableorlist and writes a new table (or list) that consists of each Column, in the order you list them on the command line.
If you give a column name that is not one of the columns for tableorlist, column creates a new column with that name, in that location, and leaves it empty. This lets you to create new columns. If you want to compute a column that does not exist, use this column facility to create it, then use the compute command to compute it. However, if you misspell
a column name, you will get an empty column.
If you name no Column on the command line. column writes all of tableorlist to the standard output without change.
Example
Assume that you have an inventory table. as follows:
*— PDF-Seite 198 · Buchseite 188 —*
```text
column
```
Item Amount Cost Value
```text
1 3 5.00 0
2 100 0.50 0
3 5 8.00 0
4 23 1.98 0
5 99 2.45 0
6 89 14.75 0
7 5 175 f°)
```
The command:
```text
Description
rubber gloves
test tubes
clamps
```
```text
plates
cleaning cloth
bunsen burners
scales
```
column Cost Amount Description \< inventory
```text
produces the following output:
Cost Amount Description
```
5.00 3 rubber gloves
0.50 100 test tubes
8.00 5 clamps
1.98 23 plates
2.45 99 cleaning cloth
```text
14.75 89 bunsen burners
175 5 scales
```
Note that the columns Cost and Amount have been reversed. We only have the columns we asked for and in the order we requested.
column can also manipulate list-formatted files. For example, the mailing list called maillist
```text
looks like this:
Number 1
Name Ronald McDonald
```
```text
Company McDonald’‘s
Street 123 Mac Attack
city Memphis
```
State TENN
ZIP 30000
Phone (111) 222-3333
```text
Number 2
Name Chiquita Banana
Company United Brands
```
Street Uno Avenido de la Reforma
```text
City San Jose
State Costa Rica
ZIP 123456789
Phone 1234
```
If you want only the names and numbers. type:
```text
column Name Phone < maillist
```
*— PDF-Seite 199 · Buchseite 189 —*
This produces the following output:
```text
Name Ronald McDonald
Phone (111) 222-3333
```
```text
Name Chiquita Banana
Phone 1234
```
See Also
```text
project, row
COHERENT Lexicon: awk
```
```text
commands — /rdb Command
Describe /rdb commands
commands
```
The command commands displays a table of /rdb commands, with a one-line description and the syntax of each command.
See Also
```text
act, helpme, rdb, whatis, whatwill
```
```text
compresss — /rdb Command
Squeeze out all leading and trailing blanks
compresss [-b] < tableorlist
```
The command compresss removes all leading and trailing blanks from every column or field in tableorlist. You an use it to save disk space.
Please note that the name compresss is not a typographical error. The command is spelled in this way to avoid collision with the COHERENT command compress, which behaves very differently from compresss.
compresss is almost the opposite of the command justify. Your files are not as pretty when compressed as they are when justified, but they are smaller — usually one third the size or less. Therefore, they take less disk space and are much faster to process; after all, most of the time used to execute data-base programs consists of moving data from the disk to the memory and, sometimes, back to the disk.
```text
Multiple blanks that separate words are left alone.
Options
```
```text
compresss recognizes the following option:
-b Drop blank lines. Don’t use this option with list files!
```
```text
Example
For example, consider table oldjournal, which is as follows:
```
*— PDF-Seite 200 · Buchseite 190 —*
```text
Date Account Debit Credit Description
890102 101 25000 cash from loan
890102 211.1 25000 loan number #378-14 Bank Amerigold
890103 150.1 10000 test equipment from Zarkoff
890103 101 5000 cash payment
890103 212.62 5000 note payable to Zarkoff Equipment
890104 130 30000 inventory - parts from CCPSC
890104 201.1 15000 accounts payable to CCPSC
890104 101 15000 cash payment to CCPSC for parts
```
```text
After we run the command
compresss
*— PDF-Seite 201 · Buchseite 191 —*
column. This command creates an empty column for any column it cannot find in the header line.
Example
```text
This example computes a column from other columns:
compute ‘Value = sprintf("%5.2f", Cost * Amount)’ < inventory
```
Item Amount Cost Value Descriptioi
```text
SI 3 5.00 15.00 rubber gloves
2 100 0.50 50.00 test tubes
```
3 5 8.00 40.00 clamps
4 23 1.98 45.54 plates
```text
5 99 2.45 242.55 cleaning cloth
6 89 14.75 1312.75 bunsen burners
7 5 175.00 875.00 scales
```
Here are more examples of what you can do with compute. You can change the format of column by using a C-style sprintf:
```text
compute ‘column = sprintf ("%8.2f", column)’ < tableorlist
You can set column equal to the length of the string in column2:
```
```text
compute ‘column = length (column2)’ < tableorlist
You can also Set column equal to the natural logarithm of column2:
```
```text
compute ‘column = sprintf("%f", log (column2))’ < tableorlist
Or, you can increment column2 whenever column is greater than number:
```
```text
compute ‘if (column > number) column2 = \
sprintf("%d", column2+1)’ < tableorlist
```
Expressions
As you can see, you can write rather complex expressions for compute. By expression, we mean many kinds of equations. For example, a variable or a column is an expression. So is variable + variable. So are rather complex equations. The following symbols indicate some of the more complex expressions:
```text
column
Name of a column, exactly as it appears at the top of the column.
```
= Make the column on the left equal the expression on the right.
+ Add
- Subtract
Multiply
```text
/ ‘Divide.
```
% Modulo (zero if left value is equally divisible by right).
Statement separator needed if more than one equation
*— PDF-Seite 202 · Buchseite 192 —*
```text
compute
```
```text
log()
Natural logarithm of value or column within parentheses.
```
```text
length0
String length of string in column.
```
You can also use C language-like statements:
```text
if (expression) equation [ else equation };
For example:
```
```text
if (Value > 10000) Status = "Special"; else Status = "Normal";
while (expression) equation;
```
For example:
```text
while (column => 0) column -= 1 ;
```
```text
for (expression; condition; expression) equation;
For example:
```
```text
for (i = 0; i < columnl; i++) array [i] = column2 + i ;
You can also use the awk format pattern { action}. For example:
compute ‘length > 80 { print NR, "Line too long." }‘ < table
```
awk recognizes length as a function that returns the length of the row and NR as the line number, Note that the line numbers of a file starts with the head line, while row numbers of a table starts after the dash line (line 3).
## What Is a Column Name?
compute looks up, in the column header of the input file. each word that it finds in its command-line program. If there is a match, compute converts the column name to its position (first, second, third, etc.) depending upon the relative location of the column. These column numbers are needed by awk.
compute defines a column name to be a string of the following characters:
1. Upper and lower letters, numbers, and the underscore \*\_’.
2. Any string that is enclosed by apostrophes or quotation marks.
Therefore, if you want special characters in your column names, put quotation marks around them when you use them. For example:
```text
compute ’ “Item#" = NR ’ < inventory
```
Note the quotation marks around the column head Item# because of the number character ‘#’, Also, note that we used quotation marks, because the whole program was enclosed in apostrophes. If you use one kind of mark around the whole program, use the other kind of mark around the column names that have special characters in them.
## Reserved Words to Avoid in Column Names
Some words are understood by awk. Therefore, they should not be used in column names. A simple way to avoid a conflict is to start your column names with a capital letter. awk does not confuse Print with print. Here is a list of awk’s built-in functions.
Reserved Words Description
```text
BEGIN.. Patternthat matches before first input record
Patternthat matches after last input record
...Getout of for or while loop
```
*— PDF-Seite 203 · Buchseite 193 —*
..Goto next iteration of for or while loop
```text
Usedin "if then else" expression
```
```text
Leaveprogram entirely as if end of input
Raisenumber to a power
```
```text
for{ expression ; condition ; expression ) statement
.Getnext input line
```
if{ condition ) statement [ else statement ]
```text
for{ variable in array ) statement
```
```text
index( string], string2 )
```
Truncateargument to integer
```text
Returncurrent line length, or length of argument
Returnlog (to base 2) of argument
```
```text
Skipto next record and reexecute all commands
Outputvariables
```
```text
printf{"format", variable, ... )
```
```text
split( string. arrayname, separator)
sprintf("format", variable, ... )
```
Returnsquare root of argument
```text
substr( string, start. number )
```
-while( condition ) statement
```text
Programs
Often you want to use a shell variable in a compute command. It is easy, if you
understand what is going on. For example, the following commands:
```
```text
DATE=860101
compute "Date = $DATE" < journal
produce the following output:
```
Date Account Debit Credit Description
860101 101 25000 cash from loan
```text
860101 211.1 25000 loan number #378-14 Bank Amerigold
860101 150.1 10000 test equipment from Zarkoff
860101 101 5000 cash payment
```
```text
860101 211.2 5000 note payable to Zarkoff Equipment
860101 130 30000 inventory - parts from CCPSC
860101 201.1 15000 accounts payable to CCPSC
```
860101 101 15000 cash payment to CCPSC for parts
We set a shell variable named DATE to a date. Then we used the variable in the compute command line program. But note that we had to use quotation marks (") instead of our usual apostrophes (’). To the shell, apostrophes protect absolutely. With apostrophes, the shell would not see the dollar sign ‘S’ in front of DATE and would not convert it to its value. The quotation mark protects the enclosed from the shell, also, except for shell variables and command substitution (‘cmd'). With quotation marks, the shell will still replace variables (which start with a dollar sign character).
There is one further complication. The previous worked fine because the value of date was a number. But if we want to use strings in awk, they must have quotation marks (not apostrophes) around them. For example:
```text
COMPANY='Makeapile, Inc.’
compute “Company = \"$COMPANY\"" < maillist
```
*— PDF-Seite 204 · Buchseite 194 —*
produces the following:
Number 1
```text
Name Ronald McDonald
Company Makeapile, Inc.
Street 123 Mac Attack
City Memphis
```
State TENN
ZIP 30000
```text
Phone (111) 222-3333
Number 2
```
```text
Name Chikeeta Banana
Company Makeapile, Inc.
Street Uno Avenito De La Revolution
City San Jose
```
```text
State El Salvadore
ZIP 123456789
Phone 1234
```
Here we set a shell variable COMPANY to a company name. We want to update the mail list because these characters have been hired by a new company. Note what we had to do. We needed quotation marks around the whole program to let the shell substitute the value of the shell variable. But we also needed quotation marks around the string “Makeapile, Inc.” for awk. So we have to protect the innermost quotation marks with backslashes.
There is another way. which opens up a little window in the program for the shell to insert strings. But it fails when there are spaces in the window string. So use the method previously discussed.
```text
Problem With awk Floating-Point Format
```
With some implementations of awk, the value column is computed to much greater precision than you are likely to want. For example, version produces this table:
Item# Amount Cost Value Description
1 3 5.00 15 rubber gloves
2 100 0.50 50 test tubes
```text
| 5 8.00 40 clamps
```
4 23 1.98 45.539997100830078125 plates
```text
5 99 2.45 242.5499725341796875 cleaning cloth
6 89 14.75 1312.75 bunsen burners
```
7 5 175.00 875 scales
To control the precision of the floating-point values in a column, you can use the sprintf function from the C programming language that has been implemented in awk. For example:
```text
compute ‘Value = sprintf ("%7.2f", ( Cost * Amount ))' < inventory
These commands will produce the first table under Examples, above.
```
*— PDF-Seite 205 · Buchseite 195 —*
```text
See Also
COHERENT Lexicon: awk, ksh, sh
```
```text
computedate — /rdb Command
```
```text
Add given number of days to a date
computedate date days
```
The command computedate adds days to a date, and displays the new date. date must be the format YYMMDD; days can be negative or positive. computedate displays the new date in the same format. This is the best format for entering dates in a column because they sort correctly and take only six characters.
Internally, computedate converts the date to julian, adds days, then converts the date back to gregorian. Suppose we want to know the date 45 days from March 31, 1989. We can type
```text
computedate 890331 45
```
```text
This command returns the string:
890515
```
That is May 15. 1989.
Another trick is to combine the todaysdate and the computedate programs. todaysdate gives the date of today in the preferred format of YYMMDD. For example, the following command shows us the date 45 days from today:
```text
computedate ‘todaysdate’ 45
```
## Data Validation
You can use computedate to validate a date. If you add zero days to a date and get a different date, then the original date was not valid. For example, let's test the 32nd day of January 1989:
```text
computedate 890132 0
```
This returns the string 890201 or February 1, 1989. As we expected, we received a different date. We can test this with the following shell program:
```text
if test $DATE = ‘computedate $DATE 0’
then
echo OK
else
echo Invalid DATE
fi
```
```text
See Also
gregorian, julian, todaysdate
```
```text
consolidate — /act/g] Command
Combine all subsidiary journals to general journal
consolidate nextdate
```
The command consolidate is part of the accounting/general-ledger system that is included with /rdb. It assembles all of the subsidiary journals, such as journalincome, journalexpense, and journaldeposit, into the general journal named journal. It also converts from single-entry to double-entry bookkeeping by totaling Debits and Credits and
*— PDF-Seite 206 · Buchseite 196 —*
```text
cpdir.rdb
```
inserting counterbalancing adjustments to the cash account. It needs the nextdate for these accounts.
Example
```text
The command
consolidate $NEXTDATE
writes into file journal data that resemble the following:
```
Date Account Debit Credit Ref Description
```text
890101 4370 2 Fe parking at clients
890103 4380 15 e115 shuttle bus to airport
890104 4380 a3 v meal
```
890105 4380 13 c116 meal
890106 4384 114 r hotel
890118 3100 3286 c101 consulting
890125 3080 250 c1459 book fees
891231 1010 5858 double-entry
891231 1010 17036 double-entry
```text
891231 3010 13500 deposit from sales/deposit
891231 4020 3601 check from pur/check
891231 4030 2100 payroll from pay/journalpay
```
Note the double-entry adjustments, and the totals of journals from sales, purchasing, and pay departments. The Date came from the NEXTDATE shell variable. which you must set in your .profile.
See Also
```text
getjournal
```
```text
cpdir.rdb — /rdb Command
```
```text
Copy one directory tree to another directory
cpdir.rdb fromdirectory todirectory
```
The command cpdir.rdb copies a directory tree — that is, all directories and their files — from fromdirectory to todirectory.
cpdir.rdb uses the tar command in a special way. It is a shell program so you can read it and see how it does it. It performs almost exactly the same work as the COHERENT command cpdir.
```text
Example
You might use this to back up a large directory:
```
```text
cpdir.rdb /usr/rdb /usr/rdb. backup
The following moves a directory to a preferred place:
cpdir.rdb /usr/he,left/goodstuff /usr/project/goodstuff
```
```text
See Also
COHERENT Lexicon: cpdir, tar
```
*— PDF-Seite 207 · Buchseite 197 —*
Notes This command is named cpdir.rdb rather than cpdir, as in other implementations of /rdb, to avoid clashing with the COHERENT command cpdir.
```text
cstate — /act/sales
Produce customer statement
cstate
```
The command estate is part of the accounting/sales system that is included with /rdb. It generates the customer statement from the tables salesorder and deposit. It shows what the customer has ordered and paid, and the net. The result is printed as a form to be sent to the customer as a bill. Example The following gives an example of the output of cstate: Please enter customer number (or all or Return to exit): 3
Customer Statement
```text
Makeapile, Inc., 123 Bigbucks Blvd., Dallas, TX 12345, 1-800-SOF-WARE
Mailing Address for Customer Number 3
Ms Ute Unix Ph.D. President
```
```text
UniUniUniUni Software Sellers
12345 Nixuni Street
Union, New Jersey 11111 USA
```
Now Due and Payable is your balance of: 107550.00
Details of Your Orders and Payments
```text
Cust Date Amount Ref
3 850902 -6300.00 17
3 850902 -14175.00 16
3 850902 -22050.00 4S:
3 850902 -23625.00 12
3 850902 -37800.00 13
3 850903 -12600.00 23
3 860105 9000.00 3347
```
-107550.00
Please enter customer number (or all or Return to exit):
See Also
```text
act, vstate
```
```text
cursor — /rdb Command
Move the cursor to the row and column requested
cursor row col [ CURSOR }
```
The command cursor move the cursor to screen position row and column. You can cursor and the /rdb command clear.rdb to perform complex screen handling from within a shell
*— PDF-Seite 208 · Buchseite 198 —*
script. You can paint your screen with cursor moves and echo commands; then use the read command to read the user's input; and finally use various COHERENT and /rdb commands to examine and confirm the input. You can also clear fields of the screen by moving the cursor and writing blanks.
You must give the row and column you want. cursor also needs the cursor movement (cm) entry from file /etc/termcap. This can be given as an argument, but the easiest way is to set up the shell variable called CURSOR then cursor will find it in its environment automatically. To set up the CURSOR variable, do the following:
```text
CURSOR=‘termput cm’
```
Another way is to use your text editor to find the entry in /etc/termcap and copy its cm entry for your terminal to your .profile:
```text
CURSOR=“[ [ $p1d; 8p28dH
```
This is the entry for the pe terminal. The uparrow bracket (“[) is the ESC character (\). The function tgoto function from the termcap library converts it into the proper escape string.
```text
Example
The following moves the cursor to the middle of an 80-by-24 screen:
```
```text
cursor 11 38
Speed
```
cursor is fast, but there is a much faster way. Set a shell variable like L22 to move to the 22nd line:
```text
L22=‘cursor 23 0’
Then you can use:
echo “$L22$MESSAGE\c"
```
in your shell programs for a fast cursor movement and to print a message. Note the quotation marks around the messages in case there are special characters. Also note the \\¢e, which tells echo not to print a carriage return.
An even better trick is to use the shell feature that tests to see if a variable has been set and only gives it a value when it needs one:
```text
echo "${L22:=‘cursor 22 0‘}$MESSAGE\c"
```
All of this magic causes the shell to check if L22 has a value. If not, it executes the cursor command and assigns the value to L22. Then, if this line is called in a loop, the next time the value will have been set and will be about 20 times faster.
See Also
```text
termput
COHERENT Lexicon: .profile, termcap
```
*— PDF-Seite 209 · Buchseite 199 —*
D
dash line — /rdb Definition The dash line is the second line in an /rdb table. It underscores each entry in the table's head line. Each entry in the dash line must be separated by a tab character. Example The table inventory appears as follows:
```text
Item Amount Cost Value Description New
1 3 50 150 rubber gloves
2 100 5 500 test tubes
3 5 80 400 clamps
4 23 19 437 plates
5 99 24 2376 cleaning cloth
6 89 147 13083 bunsen burners
7 5 175 875 scales
```
The dash line is:
Note that there is one entry in the dash line for each entry in the head line.
```text
See Also
head line, listtotable, tabletolist
```
```text
datatype — /rdb Command
Display the data type of each column selected
datatype [-1] [column...] < table
```
The command datatype displays the type of data contained in each column. If you do not name a column on the command line, datatype calculates and displays all of table's columns.
Options The -1 option tells datatype to print the entire contents of table, in addition to information about each column.
Code
-1 Character strings with nonnumeric data.
0 Integer number.
1,2... Floating-point number (number of digits to the right of the decimal).
```text
Example
The following shows a sample output of datatype:
```
*— PDF-Seite 210 · Buchseite 200 —*
```text
Int Char Float2 Float4
1 a 1.2 1.1234
745 ZZ2Zz 8.54 12.3
```
```text
to) -1 2 4
```
Note that the Int column has only integers in it (code 0), the Char column has characters in it (code -1), and the two Float columns have different precisions (positive numbers codes). Note that the float precision is the maximum.
```text
See Also
ascii, chr, dbdict
```
dBASE crossreference — Technical Information dBASE was developed and marketed by Ashton-Tate; this company was purchased recently by Borland International.
The following table gives the /rdb and COHERENT equivalents for most common dBASE commands. The slug in bold characters gives the dBASE command; the following description gives the equivalent in /rdb and COHERENT commands:
```text
ACCEPT Comment TO Variable
echo Comment ; read Variable
```
```text
APPEND BLANK
echo >> Fileout
```
```text
APPEND FROM Filename FOR Condition
row ‘Condition’ < Filename >> Fileout
```
```text
BROWSE
more, scat, update, or any text editor
```
```text
CANCEL
DEL (any character set with stty)
```
```text
CHANGE Range FIELD Fieldname FOR Condition
compute ‘Range && Condition {Fieldname = Value}' < Filein
```
```text
CLEAR
CLEAR GETS
clear
```
```text
CONTINUE
continue [shell statement]
```
```text
COPY TO Filename FIELD Fieldnames FOR Condition
row ‘Condition’ < Filein | column Fieldnames > Filename
```
```text
COUNT FOR Condition TO Variable FOR Condition
row ‘Condition’ < Filein | tail +3 | we -1
```
```text
CREATE Filename
> Filename ; vi Filename ; ve Filename ; cmd > Filename
```
```text
DELETE RECORD Number
(sed SNUM+1}q Filename ; tail +S NUM+3}) > tmp; mv tmp Fieldname
```
*— PDF-Seite 211 · Buchseite 201 —*
```text
DELETE NEXT Number
DELETE ALL
sed 2q Filename > tmp ; mv tmp Filename
```
```text
DELETE NEXT Number FOR Condition
DELETE FILE Fieldname
> Filename
```
```text
DISPLAY Range FOR Bedingung Field OFF
row ‘Range && Dedingung’ < Filename | column Fieldnames
```
```text
DISPLAY STRUCTURE
for I in * do sed 2q; done
```
```text
DISPLAY MEMORY
df; du
```
```text
DISPLAY FILES ON Disk LIKE Datatype
Is *Datatype ; ls Disk/*Datatype
```
```text
) Program
Program
```
```text
CASE Condition
Condition) [shell case statement]
```
```text
OTHERWISE
*) [shell case statement]
```
```text
DO WHILE Condition CR ENDDO
while Condition CR do done
```
```text
EDIT
vi, ve, update, ex, ed, me, other editors and commands
```
```text
ECT
ENDDO
do [in shell while, until, for statements]
```
```text
ERASE
clear
```
```text
FIND Text
/Text (in vi, ve, update)
```
```text
INDEX ON Fieldname TO Filename
index Filename Fieldname ...
```
```text
USE Filename INDEX Keyfield
search Filename Keyfield
```
```text
INPUT Text To Variable
Variable=Text
```
```text
INSERT
sed ${NUM}q Filename; echo SRECORD; tail +$NUM Filename
```
```text
JOIN TO Filename FOR Condition FIELDS Fieldnames
jointable Filename1 Filename2
row ‘Condition’ < Filename2 | jointable Filename] -
column Fieldnames < Filename2 | jointable Filename -
```
*— PDF-Seite 212 · Buchseite 202 —*
```text
dBASE crossreference
```
```text
Column,Row SAY Comment GET Variable PICTURE
tput Column ; tput Row ; echo Comment ; READ Variable
```
GO
GOTO
```text
GO RECORD n
ve nG
```
```text
GO Fieldname
ve /
```
```text
GO TOP
ve H
```
```text
GO BOTTOM
ve L
```
```text
IF Condition Statement2 ELSE Statement2 ENDIF
if Condition then Statement] else Statement? fi
```
LOCATE FOR Condition
```text
row ‘Condition’ < Filename
LOOP
```
```text
while, until. for [shell statements]
MODIFY STRUCTURE
```
```text
column New Fieldnames < Filename
NOTE
REMARK
```
```text
: Old Comment
# New Comment
```
```text
MOVE Old-Filename TO New-Filename
mv Old-Filename New-Filename
```
```text
REPLACE Range Fieldname WITH Expression FOR Condition
compute ‘Fieldname = Expression’ < Filename
compute ‘Range && Condition {Fieldname = Expression}’ < Filename
```
```text
REPORT Form FOR Condition TO PRINT
report Form < Filename
row ‘Condition’ < Filename | report Form | print
```
PACK
```text
compress, uncompress [COHERENT]
QUIT
```
```text
```
```text
READ
read Variable
```
```text
RECALL Condition
row ‘Condition’ < Filename
```
```text
RELEASE Variable
Variable=
```
```text
RESET
RESTORE FROM Filename
```
*— PDF-Seite 213 · Buchseite 203 —*
```text
RETURN
return [shell]
```
```text
SAVE TO Filename
SELECT
row, column, etc.
```
```text
SET
set [shell]
SKIP
```
```text
SORT ON Fieldname TO Filename
sorttable Fieldname > Filename
```
```text
STORE Expression TO Variable
Variable="Expression’
```
```text
SUM Fieldname TO Variable FOR Condition
Variable='row ‘Condition’ < Filename | column Fieldname*
```
```text
TOTAL ON Keyfield TO Filename FIELDS Fieldnames FOR Condition
row ‘Condition’ | subtotal Keyfield Fieldnames > Filename
```
```text
UPDATE FROM Filename ON Keyfield
update, vi, ve, replace, append, delete, etc.
```
```text
USE Filename
cmd < Filename
```
```text
WAIT
wait [shell]
```
```text
@ Row,Column SAY expression
cursor Row Column; echo EXPRESSION
ve screen and validation file
```
All data-base systems have some method for importing text files. Sometimes you'll be able to use the header information that comes with /rdb tables, and sometimes you'll have to specify this information to the target system anyway.
```text
dbdict — /rdb Command
```
```text
Print a data-base dictionary
dbdict < table
```
The command dbdict prints a table of two columns: The first gives the names of each field in table, and the second gives the field numbers.
```text
Example
For example. we might have a table named journal that looks like this:
```
*— PDF-Seite 214 · Buchseite 204 —*
Date Account Debit Credit Description
861222 101 25000 cash from loan
```text
861222 211.1 25000 loan number #378-14 Bank Amerigold
861223 150.1 10000 test equipment from Zarkoff
```
861223 101 5000 cash payment
```text
861223 211.2 5000 note payable to Zarkoff Equipment
861224 130 30000 inventory - parts from CCPSC
861224 201.1 15000 accounts payable to CCPSC
```
861224 101 15000 cash payment to CCPSC for parts
```text
The command
dbdict < journal
produces the following:
```
```text
field name
1 Date
```
2 Account
3 Debit
4 Credit
5 Description
```text
delete — /rdb Command
Blank record and update index file
delete [-m[bhirs]] table keycolumn ... < keytable
```
The command delete writes a blank record on the row in table whose key matches the row in the keytable. It also deletes the offset row in the appropriate fast-access offset table. or, in the case of the hash method, replaces the deleted offset with -1.
Options -m[bhirs] lets you select a type of fast-accessing to locate the row to delete. For information on the type of fast accessing that each option invokes, see the manual entry for index.
```text
Example
Consider table inventory. which appears as follows:
```
Item Amount Cost Value Description
```text
1 3 50 150 rubber gloves
2 100 5 500 test tubes
```
3 5 80 400 clamps
4 23 19 437 plates
```text
5 99 24 2376 cleaning cloth
6 89 147 13083 bunsen burners
7 5 175 875 scales
```
The record index looks like this:
*— PDF-Seite 215 · Buchseite 205 —*
```text
Offset
76
```
```text
113
147
177
207
245
283
```
```text
The following command deletes the first record Item1:
echo 1 | delete -mr inventory Item
```
inventory now appears as follows:
```text
Item Amount Cost Value Description
2 100 5 500 test tubes
3 5 80 400 clamps
4 23 19 437 plates
5 99 24 2376 cleaning cloth
6 89 147 13083 bunsen burners
7 3 175 875 scales
```
```text
inventory.r now appears as follows:
Offset
```
```text
113
147
197
207
245
283
```
Note that we have blanked out the record and removed the offset.
```text
See Also
append, index, replace
```
```text
difference — /rdb Command
Output table of rows that are in only one table
difference table1 table2
```
The command difference uses the COHERENT commands sort and uniq to subtract logically table2 from table1. Its output consists of the rows that are in table] but not in table2. The two input tables must have the same columns (union compatible in the technical data-base literature), and the rows must be exactly identical — including every space, tab, and nonprinting character. If two rows look the same to you but not to difference, try the see command to discover any blank spaces and nonprinting characters.
*— PDF-Seite 216 · Buchseite 206 —*
Example
In this example, consider the table journal, which appears as follows:
Date
Amount
Account Ref
Description
```text
820107
820113
820114
820114
820119
820121
820121
820125
```
```text
2500.00
99.00
```
```text
keogh
dues
```
¢adcaaade
```text
meal with jones
```
```text
car repairs
```
```text
car insurance allstate
```
```text
car registration dmv
```
```text
sundown vitamins
```
```text
meal with scott
```
```text
keogh payment
```
```text
dues to uni-ops unix conference
```
And consider the table carexpense, which appears as follows:
Date
Amount Account Ref
Description
```text
820113
820114
820114
```
```text
101.62
81.80
93.00
```
The command
```text
car
insur
car
```
```text
car repairs
car insurance allstate
car registration dmv
```
```text
difference journal carexpense
```
logically “subtracts” carexpense from journal, to produce the following output:
Date
Amount
Account Ref
Description
```text
820107
820119
820121
820121
820125
```
See Also
```text
14.00
81.72
20.83
2500.00
99.00
```
```text
meal
vitamin
meal
keogh
dues
```
```text
Vv
c
Vv
c
Vv
```
```text
meal with jones
```
```text
sundown vitamins
```
```text
meal with scott
```
```text
keogh payment
```
```text
dues to uni-ops unix conference
```
COHERENT Lexicon: diff, diff3, sort, uniq
```text
display — /rdb Command
Write table or list file to standard output
display < tableorlist
```
The command display copies tableorlist from the standard input to the standard output. This is not a very useful program, but is a template for the C interface programs. If you have its source code, you have an example of how to process tables and lists and can modify it for your own programs.
display is slower than the COHERENT command cat because it does more processing. display knows about table and list formats, and reads and writes one row at a time.
See Also
COHERENT Lexicon: cat, more
*— PDF-Seite 217 · Buchseite 207 —*
```text
domain — /rdb Command
```
```text
Display invalid values in a column
domain domaintable [string ...] [< one-column-table]
```
The command domain displays all strings or all rows in one-column-table that do not match any entry in the domaintable.
domain is useful for validating that each item in a column is legitimate. First. build a file that consists of a list of all legal values. In relational theory, these values are called the domain of the column. (You can also use the command validate to validate numbers and short lists of valid strings.)
To check the domain of a column in a multicolumn table. simply use the command column to project the column you want.
The domaintable must be sorted because it be searched by the command search using the binary fast-access method (-mb). domain is a shell script, so you can edit it to change its search method,
Example
You might have an order file for cars like this:
```text
Qty Model Colors Options
1 sedan black 3
1 sedan green 1
1 sedan farble 4
3 sedan red 5
2 convert white 1
1 sedan purple 2
1 sedan yellow 4
3 convert blue 2
```
You would also need a sorted file of possible car colors:
```text
silver
white
```
```text
Now we can validate the Color column and see all unacceptable colors:
column Colors < orders | domain colors :
```
This produces the following output:
*— PDF-Seite 218 · Buchseite 208 —*
Colors
domain complains about farble and yellow because neither color is in our domain list.
You can invoke orders in the text editor and edit it, or add those colors to the approved list. In vi use the /pattern command to find all of the patterns in the orders file. Another approach is to type something like this:
1g/farble/s//purple/g
This vi command will find all instances of farble and change them to purple.
You can also validate strings written on the command line. For example, the command domain colors red blue purple farble yellow green
also prints the output:
```text
farble
yellow
```
These command-line stings should be quoted if they have any special characters in them. They are sought by the command grep. If they contain a dollar sign ‘$', it should be protected with three backslashes: this expression is scanned both by the shell and by grep, and it takes three backslashes to get one backslash through to grep.
See Also
```text
column, search, validate, ve
COHERENT Lexicon: egrep, grep, sort, uniq
```
*— PDF-Seite 219 · Buchseite 209 —*
```text
enter — /rdb Command
Add rows to a table or list file without an editor
enter [-limit] tableorlist
```
The command enter is a simple way to append one or more rows to the end of tableorlist. It displays each column name and waits for you to type each item.
enter is a substitute for the form-editor ve. It is easier to use, but very limited.
Note that this is one of the few /rdb commands that does not use the less-than symbol ‘\<’ to input a table, but requires the name of a table to which it is to append data.
If you make an error in entering a record, you can return to the last line by typing a caret ‘\*\*; enter then prompts you with the previous line. If you return two lines, keep typing carets until you are prompted for the line you wish to reenter.
Options The option -limit lets you limit the number of rows to be entered. For example, -1 prompts for one row and then exits. Thus, it can be used in a shell script.
Rules To set up and enter a file in list format instead of table format, there are several rules and suggestions.
First. let's discuss terminology. A list is like a table that is turned sideways. For example, a wide table looks like this:
```text
Number Name Company Street City State ZIP
Phone
```
```text
1 Ronald McDonald McDonald’s 123 Mac Attack
Memphis TENN 30000 (111) 222-3333
```
Note that the row is so long that it wrapped around to the next line. Also, the column names and column data do not line up. Names, Companies, and Street Addresses are usually too long to fit nicely into such a table. Therefore, we need a list format like this:
Number 1
```text
Name Ronald McDonald
Company McDonald’s
Street 123 Mac Attack
city Memphis
```
State TENN
ZIP 30000
Phone (111) 222-3333
These two formats (table and list) are made interchangeable by using two programs: listtotable and tabletolist. You can enter and keep a file in list format. When you want to use several commands, you can convert it to table format and pipe it into the regular commands for faster execution. For example, the command
listtotable \< maillist | column Name Phone | justify
*— PDF-Seite 220 · Buchseite 210 —*
produces the following output:
Name
Phone
Ronald McDonald (111) 222-3333
It is best, therefore, to remember that Name and Phone are column names. The information that follows them in the list is the first row of a table (that can be created by the
command listtotable).
1. First use an editor to create the list file. Type each column name followed by one, and only one, tab. Also enter the information for the first row (record).
2. Be sure to put a newline (blank line) as the first line of the file.
3. Be sure to put a blank line at the end of each row (record). In the previous example, it should appear after the row Phone. This tells the program that it has reached the end of the row.
You can then save the file and use the enter program. Type:
```text
enter maillist
```
## Name _
enter responds with the first column name and a tab, and waits for you to enter whatever you wish for Name. The underscore ‘\_’ shows where the cursor of your terminal will be waiting for you to input data.
4. Type in your data for the item. Use the return key to end the information for this item. If you type more than 80 characters or so, your terminal will wrap around. You can continue to type and wrap around until you reach your editor's line limit or press \. Then enter gives you the name of the next column head. a tab, and waits for your entry.
5. When enter has given you the first column name of a new record and is waiting for a response, exit from it by typing \. enter then returns you to the COHERENT shell.
For list-formatted files, it is better to use the enter command than an editor. If you do your entry with a text editor, you must include all of the column names, in the same order and spelled correctly.
Example
To add a line to file maillist, type the following:
```text
enter maillist
```
The editing session may go as follows:
*— PDF-Seite 221 · Buchseite 211 —*
Number 2
Name Chiquita Banana
Company Standard Brands
Street \*
Company United Brands
Street Uno Avenido de la Reforma
```text
City San Jose
State Costa Rica
ZIP 123456789
```
Phone 1234
```text
Name
```
Note we made an error entering Company and did not realize it until we were at Street. We typed a caret \*\*' that reprompted us for Company, which we then reentered. enter then went on to prompt us for Company again.
The entered file now appears as follows:
Number 1
```text
Name Ronald McDonald
Company McDonald’s
Street 123 Mac Attack
City Memphis
```
State TENN
ZIP 30000
Phone (111) 222-3333
Number 2
Name Chiquita Banana
Company United Brands
Street Uno Avenido de la Reforma
```text
City San Jose
State Costa Rica
ZIP 123456789
```
## Phone 1234
Note that the last row (actually eight lines and the bottom newline) is the one we entered. Just press \ if you have no data to enter after a prompt.
Now for an example of entering a table. If you want to add a line to inventory. type:
```text
enter inventory
```
Item# Amount Cost Value Description
Then start typing your rows. Remember to insert tabs between columns:
```text
8 123 5.98 [) widget
9 29 15.50 t) another widget
```
*— PDF-Seite 222 · Buchseite 212 —*
```text
The inventory file now looks like this:
Item# Amount Cost Value Description
```
```text
1 3 5.00 0 rubber gloves
2 100 0.50 [¢) test tubes
```
3 5 8.00 0 clamps
4 23 1.98 0 plates
```text
5 99 2.45 0 cleaning cloth
6 89 14.75 0 bunsen burners
7 5 175 0 scales
```
8 123 5.98 0 widget
```text
9 29 15.50 0 another widget
Note that the last two lines are the ones we entered.
```
See Also
```text
listtotable, tabletolist, ve
```
```text
explode — /rdb Command
Produce table of subparts and their count for a part
explode Part Amount [ table ]
```
The command explode takes a part number or name and looks it up in a part table to find all of its subparts. It then finds the subparts of those subparts, and so forth, until it can seek no farther. explode also multiplies the number of parts times the subpart counts at each interaction, so the final subpart table lists all of the subparts of the original part and the total number of subparts needed to make the part.
You can use explode to generate a list of all items needed to make a product. The cost of these subparts, times the count. gives the value that can be totaled to arrive at the total cost of the product.
explode assumes that the Part, Subpart, and Count columns are the first three columns of the table, and that the third column is actually named Count.
```text
Example
If you had a parttable, like this:
```
Part Subpart Count
```text
10001 10010 3
10001 10020 4
10010 10100 2
10020 10100 5
```
```text
and you wanted to find the subpart list and count for two part 10001s, you would type:
explode 10001 2
```
The result would be:
*— PDF-Seite 223 · Buchseite 213 —*
Part Amount
```text
10001 2
10010 6
10020 8
10100 52
```
Note that both 10010 and 10020 have 10100 as a subpart, but explode uses subtotal to combine the 10100 subparts into one row. The table is also sorted.
```text
See Also
bom, subtotal
```
*— PDF-Seite 224 · Buchseite 214 —*
```text
fd
```
```text
fd — /rdb Command
```
```text
Test for functional dependency of columns
fd determinecolumn dependcolumn < table
```
The command fd reads table and tests whether its determinecolumn determines dependcolumn. A column in a table functionally depends upon another column when there is only one value in the second column for each value in the first. This helps you to determine if a table is normalized. (See the section on Normalization, below, for details on what this means.)
```text
Example
First let's look at our inventory table:
```
```text
Item Amount Cost Value Description
1 3 50 150 rubber gloves
2 100 5 500 test tubes
3 5 80 400 clamps
4 23 19 437 plates
5 99 24 2376 cleaning cloth
6 89 147 13083 bunsen burners
y 5 173 875 scales
```
Note that the first column, Item, is the key column for the table. It functionally determines all of the other columns. Each value in column Item is unique. so each value determines, or is the key, to its row and all of the column values on it.
However, column Cost does not functionally depend upon Amount because there are two ‘5’ values in Amount and each has a different value for Cost associated with it (on the same row or line). The common sense (technically called the “semantics”) of the table is that knowing the number of items we have in inventory does not tell us how much they cost.
```text
Now let's see if fd can find the dependencies. The command
fd Item Cost < inventory
```
returns the message true. This is correct, because Item is the key column. However, the command
```text
fd Amount Cost < inventory
```
returns the message false. This, too, is correct.
Normalization
A key column should aways functionally determine all of the other columns in the table. But nonkey columns should not depend upon each other.
If there are too few data in the table, a pseudo-dependency may be discovered. Be sure your table has lots of data before you test it.
To normalize your tables, you must check for functional dependencies. When functional dependency is found with non-key columns, the columns should be projected and uniqued to form a second table. Then the functionally dependent column, but not the determining column, should be removed from the first table. For example:
*— PDF-Seite 225 · Buchseite 215 —*
```text
column columnl column2 < table | uniq > newtable
column ‘sed 1q table | sed s/column2//‘ < table > tmp
mv tmp table
```
In the second table, the column that determines the other column is the key for that table. If you need to recreate the original first table. you can join the two new tables by using the command jointable, as follows:
jointable -j columnl table newtable \> oldtable
Normalization, or simplification, is an important process. Normalized files are smaller and are easier to maintain.
See Also
```text
column, jointable, paste.rdb
COHERENT Lexicon: cut, false, mv, paste, sed, true
```
```text
filesize — /rdb Command
```
```text
Return the number of characters in a file
filesize file ...
```
The command filesize displays the number of bytes in each file. It is much faster than the COHERENT command we because it uses the system call stat() to get the number from the i-node table, rather than counting the bytes in the file.
If you ask filesize to size only one file, it sends one number to the standard output. This number can be assigned to a shell variable. With more than one file, it produces a table of sizes.
Example The following command returns the size of file filesize.1, which holds the “raw” form of what you are reading:
```text
filesize filesize.1
```
```text
This displays one value on the standard output, e.g.:
532
```
```text
The following command asks for the size of files ascii.1 and filesize.1:
filesize ascii.1 filesize.1
```
This form of the command returns a tabular output, e.g.:
Offset Filename
```text
464 ascii.1
532 filesize.1
See Also
```
COHERENT Lexicon: Is, stat), we
*— PDF-Seite 226 · Buchseite 216 —*
```text
fillform — fixtotable
```
```text
fillform — /act/g] Command
```
```text
Fill a tax from with adjusted trial balance data
fillform form
```
The command fillform is part of the accounting/general-ledger system included with /rdb. It fills in the tax form form, which must be one of 1120 (corporate), 1120S (S corporation), C (schedule C), or partnership tax form. It writes its output into a file with the name form.
```text
Example
The following example fills in the S corporation form:
```
```text
fillform 1120s
```
```text
When you post-process the output with the command
sed 10q 1120S
```
you see output that resembles the following:
Taxline Amount Description
10la 13500 Sales
```text
101b 0 Returns and Allowances
10lc 13500 Net Sales
```
```text
102 0 Cost of Goods Sold
102-Al 20000 Beginning Inventory
102-A2 3601 Misc Merchandise
102-A3 2100 Salaries and Wages
102-A4 0 Other Costs
```
See Also
```text
calculate
```
COHERENT Lexicon: sed.
Notes
Please note the tax tables and forms included with /rdb are from 1987. These are examples, and no claim is made for their accuracy in computing this year’s taxes. Caveat ulilitor.
```text
fixtotable — /rdb Command
```
```text
Converts fixed length format to /rdb table format
fixtotable column[=n1,n2] ... < fixtdb
```
The command fixtotable converts a data base from fixed-length format to variable length /rdb format. It does so by selecting n2 bytes of data from table fixtdb, beginning at the n1 position for each column specified. It inserts tabs between columns and calls the /rdb command compress to remove leading and trailing blanks. It generates header records from the column names. Column names that do not specify start position (nl) and field width (n2) are considered empty columns, and appear as such in the output. Blank records are removed.
Example
For example, let's look at a file named journal:
*— PDF-Seite 227 · Buchseite 217 —*
```text
foot —
```
```text
1 10 20 30
wanntenn|aaantenne|-too=|
820102101 25000
820102211.1 25000
820103150.1 10000
```
```text
820103101 5000
820103211.2 5000
820104130 30000
```
The first six bytes are the date field; the next six bytes, starting at position 7 are the account number field; the next seven bytes, starting at position 13 are the credit field; and the last seven bytes, starting at position 20 are the debit field.
The following command yanks the account number and the credit and debit fields from journal, makes a new table with a new field for the description:
```text
fixtotable Account=7,6 Debit=13,7 Credit=20,7 Description < journal
This produces the following table:
Account Debit Credit Description
```
101 25000
```text
211.1 25000
150.1 10000
```
101 5000
```text
211.2 5000
130 30000
```
See Also
```text
compress, tabletofix
```
```text
/act/gl Command
Foot or subtotal Debits and Credit of ledger
foot
```
The command foot is part of the accounting/general-ledger system included with /rdb. It subtotals the accounts in table ledger.
Example
The command foot produces a table that resembles the following:
```text
Account Date Debit Credit Ref Short Description
1010 851231 1758 cash
```
1010 851231 5137 cash
1010 5137 1758
3010 1601 deposit sales
*— PDF-Seite 228 · Buchseite 218 —*
850125
```text
c1459 royalty book fees
```
```text
850103
850104
850105
850106
```
```text
e115 travel
Vv travel
e116 travel
r travel
```
```text
shuttle bus
meal
```
```text
meal
```
```text
hotel
```
*— PDF-Seite 229 · Buchseite 219 —*
G
```text
getjournal — /act/gl Command
Copy journals for sales, purchasing, pay systems
getjournal journalname
```
The command getjournal is part of the accounting/general-ledger system included with /rdb. It copies, totals, and adjusts journals from other parts of the business system. These subsidiary journals are created automatically by the operations of sales, purchasing, and other departments. It also gets the inventory value for the table journaladjust.
Example
The command
```text
getjournal journaldeposit
```
reads the table journaldeposit and prints on the standard output a table that resembles the following:
```text
Date Amount Account Ref Description
891231 13500.00 sales deposit from sales/deposit
See Also
```
```text
act, consolidate
```
```text
gregorian — /rdb Command
Convert column of dates for arithmetic and format change
gregorian [ -ceu] [ Column... ] < tableorlist
```
The command gregorian converts Julian dates in one or more Columns to Gregorian date. When used with the command julian, you can do the following:
1. Add days to a date.
2. Subtract days from a date.
```text
3. Subtract two dates to find the number of days between them.
4. Change the format of a date.
```
A Gregorian date is a string that presents the date of the current year, month, and day; for example “911231". A Julian date, however, is the number of days since the beginning of the Julian calendar (January 1, 4713 BC). This system is used by astronomers, computer programmers, and other people who wish to store dates in a form that can be easily translated from one system of dating to another, without having to worry about leap years, dates of the births of religious figures, etc. Because Julian dates are integers, you can subtract one from another to find the number of days between two dates.
To perform arithmetic on dates, first use the command julian to convert the dates from Gregorian form to Julian. Then, use the command compute to add or subtract the dates (or add a constant to a date). Finally. use gregorian to convert the sum or the difference back to Gregorian form.
*— PDF-Seite 230 · Buchseite 220 —*
```text
Options
gregorian recognizes the following options:
```
-c Output computer date format, i.e., YYMMDD. /rdb uses this format by default for its Gregorian dates because it can be sorted and selected in correct numerical sequence.
```text
-e€ Output European date format. i.e.. DD/MM/YY.
-u Output U.S. date format, i.e.. MM/DD/YY.
```
Example
The first example shows how to add dates. Suppose we have a file called journal. as follows:
Date Account Debit Credit Description
861222 101 25000 cash from loan
```text
861222 211.1 25000 loan number #378-14 Bank Amerigold
861223 150.1 10000 test equipment from Zarkoff
```
861223 101 5000 cash payment
```text
861223 211.2 5000 note payable to Zarkoff Equipment
861224 130 30000 inventory - parts from CCPSC
861224 201.1 15000 accounts payable to CCPSC
```
861224 101 15000 cash payment to CCPSC for parts
Now, suppose that we want to add 45 days to each of the dates. First, see what julian does. Typing julian Date \< journal prints the following on the standard output: Date Account Debit Credit Description
1752827 101 25000 cash from loan
```text
1752827 211.1 25000 loan number #378-14 Bank Amerigold
1752828 150.1 10000 test equipment from Zarkoff
1752828 101 5000 cash payment
```
```text
1752828 211.2 5000 note payable to Zarkoff Equipment
1752829 130 30000 inventory - parts from CCPSC
1752829 201.1 15000 accounts payable to CCPSC
```
1752829 101 15000 cash payment to CCPSC for parts
The Date column now holds a Julian date. Note we gave no option because computer format is the default.
```text
The next command adds 45 days to each entry in the Date column:
julian Date < journal | compute ‘Date += 45’ | gregorian Date
```
This command prints the following on the standard output:
*— PDF-Seite 231 · Buchseite 221 —*
```text
870205
870205
870206
870206
870206
870207
870207
870207
```
Account Debit
130 30000
25000
```text
5000
5000
```
```text
15000
15000
```
Description
```text
cash from loan
```
```text
loan number #378-14 Bank Amerigold
test equipment from Zarkoff
```
```text
cash payment
```
```text
note payable to Zarkoff Equipment
inventory - parts from CCPSC
accounts payable to CCPSC
```
```text
cash payment to CCPSC for parts
```
As you can see, every date is now 45 days later than they originally were.
The next example converts one format of Gregorian date to another. To convert the Date column in our example table from computer format to U.S. format, type the following:
julian Date \< journal | gregorian -u Date | justify Date
The result is as follows:
Date
```text
12/22/86 101
12/22/86 211.1
12/23/86 150.1
12/23/86 101
12/23/86 211.2
12/24/86 130
12/24/86 201.1
12/24/86 101
```
30000
```text
Credit Description
cash from loan
25000 loan number #378-14 Bank Amerigold
test equipment from Zarkoff
5000 cash payment
5000 note payable’to Zarkoff Equipment
inventory - parts from CCPSC
15000 accounts payable to CCPSC
15000 cash payment to CCPSC for parts
```
Because the U.S. format is two characters wider than the computer format, we included the command justify in our command line to line things up.
```text
See Also
compute, computedate, julian
COHERENT Lexicon: awk, date
```
*— PDF-Seite 232 · Buchseite 222 —*
```text
hashkey — /rdb Command
```
Return the hash offset for key strings
hashkey rows keystring ...
The command hashkey adds the ASCII value of each character in the keystrings (except spaces or tabs), and returns the modulo of rows. This is for computing the hash offset into hash-index table for the hash fast-access method. It is used by the command append to
```text
update the hash-index table.
Example
```
Here we convert several characters. The command
```text
hashkey 11 ABCD
```
returns 2. (That is, ASCII values 65 plus 66 plus 67 plus 68 yields 266; which. when divided by 11 yields a remainder of 2). The command
```text
hashkey 29 abcdefg
```
returns 4.
See Also
```text
append ascii, chr
COHERENT Lexicon: ASCII
```
```text
head line — /rdb Definition
```
The head line is the first line in an /rdb table. It names each column in the table. Each entry in the head line must be separated by a tab character.
Description
```text
rubber gloves
```
```text
test tubes
clamps
```
```text
plates
cleaning cloth
bunsen burners
scales
```
Example
The table inventory appears as follows:
```text
Item Amount Cost Value
zf 3 50 150
2 100 5 500
3 5 80 400
4 23 19 437
5 99 24 2376
6 89 147 13083
7 s 175 875
```
The first line
Item Amount Cost Value
is this table's head line.
```text
See Also
dash line, listtotable, tabletolist
```
Description New
*— PDF-Seite 233 · Buchseite 223 —*
```text
headoff — /rdb Command
Remove an /rdb head from both table and list files
headoff < tableorlist
```
```text
The command headoff “beheads” tableorlist; that is, it strips off its header. Tables have
two-line colurnn heads; list files have only one line that consists of a single newline
character. The COHERENT command tail +3 does the same thing for a table; and tail +2
for a list. 7
```
The command union uses headoff to assemble files. Only the first file keeps its head. Example To behead the table inventory, type:
```text
headoff < inventory
```
This writes something like the following on the standard output:
```text
1 3 50 150 rubber gloves
2 100 5 500 test tubes
```
3 5 80 400 clamps
4 23 19 437 plates
```text
| 99 24 2376 cleaning cloth
6 89 147 13083 bunsen burners
7 5 175 875 scales
```
See Also
```text
headon, insertdash, union
COHERENT Lexicon: head, tail
```
```text
headon — /rdb Command
```
```text
Add an /rdb header to a table
headon < table
```
The command headon appends an /rdb header onto table. Tables have a two-line column head. When you have a table without an /rdb header, perhaps created by another program, you can add a head to it. You can also do this in a pipe and send the new table to other /rdb commands for processing.
Example If you want to treat the file /etc/passwd as a table for /rdb command processing, use headon, as follows:
```text
i a A ' < /etc/passwd | headon | justify
```
Note the use of the COHERENT command tr to translate a colon \*:' into a tab character; and the use of the /rdb command justify to align the columns. This produces something like the following:
*— PDF-Seite 234 · Buchseite 224 —*
```text
helpme — howmany
```
```text
root
daemon
bin
uucp
ip
guest
rod
```
```text
dVAYxSsJy10Fg
```
```text
rVOhF4 9RpZXEY
```
Be sure the first line of the table has no blank fields or headon counts the wrong number of
```text
fields.
See Also
```
3 4 5 6
0 3 Super User /
1 12 background /
2 2 binary programs /bin
```text
5 1 uucP /usr/lib/uucp
71 2 Line Printer /usr/spool/1p
100 100 Guest User /usr/guest
```
0 0 Rod Manis /usr/rod
```text
headoff, insertdash, justify, rmblank
COHERENT Lexicon: passwd, tr
```
```text
helpme — /rdb Command
List the help commands available
```
```text
helpme
```
The command helpme lists all other /rdb help commands.
Example
Typing helpme prints the following on the standard output:
Command
“commands”
```text
“whatis command"
“whatwill feature"
“man command”
```
```text
howmany — /rdb Command
Display the number of commands in a directory
```
```text
howmany
```
The command howmany displays the number of the commands it finds in directory
SRDB/bin.
```text
See Also
rdb, whatis, whatwill
```
```text
Description
a menu with some commands
```
```text
a list of the available commands
description and syntax of all the commands
description and syntax of command
```
```text
info on commands with that feature
```
```text
the manual page for that command
```
*— PDF-Seite 235 · Buchseite 225 —*
```text
index — /rdb Command
Set up table for search
index [-m{bhirs]] [-x] [-hsl [2> location]] tableorlist [keycol ...] [ < keytable ]
```
The command index sets up a table for the program search. The indexing it performs increases the speed with which search can find a row in a table or list file. This is very important for large files.
Exactly what index does depends upon the method of indexing you choose. For some methods, it builds another table, called a secondary index file, that the specified method requires. It is possible to index one file by all five methods. Some methods can index all of a table's columns.
Please note that these fast-access methods are static. If the table or list is changed — by a text editor, for example — it may have to be reindexed. Applications should manipulate the table or list files and their secondary index to update them together. Forms packages should dynamically maintain these files.
There is a trick to allow you to index any or all of the columns in a file. Simply use the COHERENT command In to link the file to as many different names as you have columns to index. Then index the table through each of its link aliases. For details, see the COHERENT Lexicon’s entry for In.
```text
Options
The following options control the method of indexing that index produces:
-m Index using the default method, which is sequential. See -ms, below.
```
-mb Binary indexing. index simply sorts the file on the specified key column. No secondary file is created. Because a file can only be sorted on one column, only one column can be indexed using this method. The command sorttable gives the same result as this option.
-mh Hash indexing. index builds a secondary-index file, named tableorlist.h, hashes all of the key-column’s values, and writes them and their offsets to the secondaryindex file. Please note that because the COHERENT system places a limit of 14 characters on a file name, the name of tableorlist must not exceed 12 characters, or index will not be able to name correctly the secondary-index file.
-mi Inverted or indexed indexing. index builds a secondary-index file of keys and offsets, then sorts on the keys. The secondary file is named tableorlist.i. The trick to index more than one column, previously discussed, alsos work for the inverted method.
If you plan on using the incomplete-match feature of search (which works only with the inverted method), you must specify the -x flag, so the secondary index is sorted
properly.
-mr Record-number indexing. index builds a secondary file named (tableorlist.r, which is one fixed-length column of row offsets.
-ms Sequential or linear indexing. index does nothing in this case, because search simply looks through the whole file.
The following options control details of index's output:
*— PDF-Seite 236 · Buchseite 226 —*
```text
index
```
-h No head line on the output table.
-l Write to the standard error the starting and stopping location of each row, and the offset entry in the secondary-index file. These numbers are used by the commands replace, lock, and unlock. The command seek uses this option to find the locations of rows. The locations are sent to standard-error device, which under the Bourne and Korn shells is file descriptor 2; thus, you can redirect them into a file by using the shell operator 2\>. You can store these data until they are needed by your shell programs.
This option produces four integers. If there is no secondary-index file, the start location is zero.
-s Only one row is found. This speeds up some of the methods because they do not have to continue searching after they find the first match. The sequential method will, on average, run twice as fast; whereas the hash, binary, and inverted methods will run slightly faster. The record-access method will not change, as it only finds one match anyway.
## Methods and Suffixes
The following gives suffixes that index appends to names of tables, in order to name its secondary-index files.
```text
Method Suffix Example
-b None a4
```
```text
-h -h inventory.h
-i ol inventory.i
-r r inventory.r
-s None
```
Example
Let's look at the first ten lines of an accounts chart, named chart:
Account Name
100 Assets
101 Cash
```text
111 Accounts Receivable
111.1 Allowance for Bad Debt
115 Notes Receivable
```
120 Deposits
130 Parts Inventory
## 150 Equipment
Access to the data in chart can be sped up by indexing it and using the command search to find the row you want. To index chart using the binary (sorted) search method, type:
```text
index -mb chart Account
```
index quietly returns when it finishes. You are now ready to use search to find an Account number in the chart See Also
```text
append, delete, lock, replace, search, unlock, update
COHERENT Lexicon: In
```
*— PDF-Seite 237 · Buchseite 227 —*
```text
insertdash — /rdb Command
Insert dash line as second line in table
insertdash < table-without-dashline
```
The command insertdash writes a line of dashes (hyphens) as the second line of the table. It makes the dash line by copying the head line and turning every character in the first into a hyphen except the tabs.
This command is useful for files created by the system or non-COHERENT programs that do not have the dash line. However, you will also need to convert field separators into tabs. You can do this with the COHERENT commands tr or sed.
Example
insertdash assumes a table that resembles the following:
```text
Item Amount Cost Value Description
1 3 50 150 rubber gloves
```
After running insertdash on it. this table looks like this:
Item Amount Cost Value Description
```text
1 3 50 150 rubber gloves
See Also
dashline, headoff, headon
```
COHERENT Lexicon: sed, tr
```text
intersect — /rdb Command
Write table of rows that are in both input tables
intersect lable] table2
```
The command intersect is a shell script that uses the COHERENT commands sort and uniq to perform a logical AND on two tables. It produces a new table that consists only of the rows that are in both of the input tables. The two input tables must have the same number of columns (called union compatible), and rows must match exactly to be considered
the same.
Example
Consider the table journal, which appears as follows:
Date Amount Account Ref Description
820107 14.00 meal v meal with jones
820114 81.80 insur c car insurance allstate
820119 81.72 vitamin c sundown vitamins
820121 20.83 meal Vv meal with scott
820121 2500.00 keogh cog keogh payment
820125 99.00 dues Vv dues to uni-ops unix conference
And consider the table carexpense. which appears as follows:
*— PDF-Seite 238 · Buchseite 228 —*
Date Amount Account Ref Description
820113 101.62 car v car repairs
```text
820114 81.80 insur c car insurance allstate
820114 93.00 car c car registration dmv
```
To see if any rows in journal are also in carexpense, type the command: intersect journal carexpense In this example, you would see the following on the standard output:
Date Amount Account Ref Description
820114 81.80 insur c car insurance allstate
As you can see, the insurance expense was already posted to the general journal.
See Also
```text
difference, jointable, union
COHERENT Lexicon: sort, uniq
```
```text
invoice — /act/sales Command
Print invoice for a sale order
invoice
```
The command invoice is part of the accounting/sales system that is included with /rdb. It prompts for the number of a sales order and then prints an invoice for that order.
Example
The following walks you through an example session with invoice:
```text
Please enter order number (or Return to exit): 1
Invoice
```
Makeapile, Inc., 123 Bigbucks Blvd., Dallas, TX 12345, 1-800-SOF-WARE
```text
Order Number 1
Date Ordered 850723
Date Shipped fo)
```
```text
Mailing Address for Customer Number 2
Customer Number 2
Mr. Thomas Boomer President
```
```text
Ye Olde Thermonuclear Bombe Shoppe
54321 Blooy Road
```
```text
Livermore, California USA
Order Number Code Backord Qty Price Total Name
1 1 rdb 10 1 1500 1500.00 /rdb
```
*— PDF-Seite 239 · Buchseite 229 —*
```text
Gross 1500.00
Tax 75.00
Total 1575.00
```
Please enter order number (or Return to exit):
See Also
```text
act, cstate
```
*— PDF-Seite 240 · Buchseite 230 —*
```text
jointable
```
```text
jointable — /rdb Command
```
Join two tables into one where keys match
jointable [-a[1 |2)] [-j[1]2] column)... -n -] table! [table2]
The command jointable joins table] to table2 on column, which is common to both tables (called the key column). If no column is named, jointable assumes that the first column in each table is the key column.
Each table must be sorted on the key column. jointable writes a new table that has one row for the rows in the tables whose values in the key column match. The columns of the new table are all the columns in table] followed by all the columns in table2— with the sole exception that the key column is not repeated.
This is called a natural join. An equi-join repeats the key column.
The COHERENT system's command join will also join two tables in the manner described above, but it does not know about /rdb head lines.
## String vs. Numeric Sort
The commonest problem seen with jointable is when users attempt to join tables that have been sorted numerically on the key columns (that is, the columns that the tables are going to be joined on). They use sorttable with the -n option (for numeric) to sort a table, then call jointable. jointable, however, expects to see a string sort fails to join the tables correctly.
The following compares a string sort with a numeric sort:
```text
String Numeric
1 1
10 2
2 10
20 20
```
Can you see why? Numeric is the way we count and is obviously correct. But string sort looks at the first character, then the second. A space sorts ahead of ‘0’, so ‘1’ comes before “10”. More importantly, ‘1’ comes before ‘2' regardless of the characters to the right. That is why “10” comes before "2" followed by a space. This problem shows up as empty output from a jointable, when you know some of the rows should be joined.
Right-justification makes numeric and string sorts the same. The leading spaces help the string sort to sort numbers correctly.
To make it easy for users to avoid this problem, jointable has the option -n, for symmetry with the COHERENT command sort.
If you want to join two tables through a numeric key column, you must either call the sorttable without its -n numeric sort option. so that it defaults to string sort: or if you use the -n option for sorttable, be sure to use it also with jointable.
```text
Options
jointable recognizes the following options:
```
-an All or one of the files (1 or 2) is output, whether it matches or not. In addition to the normal output, jointable produces a line for each unpairable line in file n, where nis 1 or 2. For example, the command
*— PDF-Seite 241 · Buchseite 231 —*
```text
jointable -al ledger chart
```
forces jointable to print every row in table ledger. regardless of whether any value in ledger’s Account column matches any value in chart’s Account column.
-jn column
Join on the column column in table number n. If n is missing, use the column column in each table. For example, the command
jointable -j1 Account -j2 account ledger chart
joins tables ledger and chart using the Account column in ledger and the account column in chart. If no columns are specified with this option, jointable joins the tables by the first column in each. Thus, this option lets you join on any column defined in either file. even when they have different names and locations.
Numeric join. This means that tablel and table2 were sorted with the numeric option -n. Remember that if you use -n with the command sorttable, you must also use it with jointable.
Read the standard input in place of a table. For example, the command
```text
sorttable < journal | jointable - chart
```
means to sort table journal, then join it with table chart so that journal is on the left of the output table and chart is on the right.
Note that this option is used only in place of tablel. If table2 is absent from the command line, jointable automatically reads the standard input for that table’s data.
\_Note that most of these options are about the same as for the COHERENT command join. Example
Consider table chart. as follows:
Account Name
Assets
Cash
```text
Accounts Receivable
Allowance for Bad Debt
Notes Receivable
Deposits
```
Parts Inventory
and table ledger. as follows:
*— PDF-Seite 242 · Buchseite 232 —*
```text
jointable
```
Account Date Debit Credit
```text
101 820102 25000
101 820103 5000
101 820104 15000
130 820104 30000
```
```text
150.1 820103 10000
201.1 820104 15000
211.1 820102 25000
211.2 820103 5000
```
Note that each is sorted in string fashion on its first column. To join them, use the command:
```text
jointable ledger chart
```
This joins the tables on the first column in each, and writes the following to the standard output:
Account Date Debit Credit Name
101 820102 25000 Cash
101 820103 5000 Cash
101 820104 15000 Cash
130 820104 30000 Parts Inventory
150.1 820103 10000 Test equipment
```text
211.1 820102 25000 Notes Payable - BA
211.2 820103 5000 Notes Payable - Z Equip
```
As you can see, column Name has been added to the columns of the ledger table, and that column Account is not repeated. Also note that jointable wrote only the rows whose values in column Account match. If a table has several rows with repeated key values (e.g., the three 101s in the Account column), the joined table’s rows are also repeated (see the three Cashs in column Name).
If you have a table named journal that is sorted on column Account, as follows
Date Account Debit Credit
820104 101
820103 101
820102 101 25000
820104 130 30000
820103 150.1 10000
```text
820104 201.1 15000
820102 211.1 25000
820103 211.2 5000
```
```text
you could join it with table chart by typing this command:
jointable -j Account journal chart
```
The following gives another way for the same result (because chart’s join column defaults to column 1):
*— PDF-Seite 243 · Buchseite 233 —*
```text
jointable -j1 Account journal chart
Both commands produce the following output:
Date Account Debit Credit Name
```
820104 101 15000 Cash
820103 101 5000 Cash
820102 101 25000 Cash
820104 130 30000 Parts Inventory
820103 150.1 10000 Test equipment
```text
820102 211.1 25000 Notes Payable - Bank of Amerigold
820103 211.2 5000 Notes Payable - Z Equipment
```
The -a option lets you see all of one table whether or not there is a match. For example, the command
```text
jointable -al ledger chart
writes the following:
Account Date Debit Credit Name
```
101 820102 15000 Cash
101 820103 5000 Cash
101 820104 25000 Cash
130 820104 30000 Parts Inventory
150.1 820103 10000 Test equipment
201.1 820104 15000
```text
ehh | 820102 25000 Notes Payable - Bank of Amerigold
211.2 820103 5000 Notes Payable - Z Equipment
```
Note that column Account’s value 201.1 in the ledger shows up here, even though it is not in chart. This shows us that 201.1 is an error. All account numbers should be in the chart of accounts. We should either add 201.1 to the chart of accounts, or find the correct number in the chart of accounts and replace 201.1 in the journal with the correct account number.
If you pipe a file into a jointable, you can control which table it will be (first or second) by using the dash option. For example:
```text
sorttable Account < journal | jointable -j Account - chart
This produces the following output:
```
Date Account Debit Credit Name
820103 101 5000 Cash
820104 101 15000 Cash
820102 101 25000 Cash
820104 130 30000 Parts Inventory
820103 150.1 10000 Test equipment
```text
820102 211.1 25000 Notes Payable - Bank of Amerigold
820103 211.2 5000 Notes Payable - Z Equipment
```
*— PDF-Seite 244 · Buchseite 234 —*
```text
julian — justify
```
Note the - before chart. It says that the standard input file will be file 1 or on the left side of the table. See Also
```text
column, sorttable
COHERENT Lexicon: join
```
```text
julian — /rdb Command
```
```text
Convert column of dates for arithmetic and format change
julian [ -ceu] [ Column... ] < tableorlist
```
The command julian converts Gregorian dates in one or more columns to Julian format. For details on the differences between Gregorian and Julian dates, and how to use these commands in scripts, see the manual entry for the command gregorian.
See Also
```text
computedate, gregorian, todaydate
```
```text
justify — /rdb Command
```
```text
Left or right justify the columns of a table
justify [-elrct'c’] [ column ... ] < table
```
The command justify right-justifies the columns that contain only numbers, and leftjustifies the columns that contain any nonnumeric characters. It also lines up floatingpoint numbers on their decimal points.
justify improves the appearance of a table. This makes it easier for you to read and edit. It also makes a column of variable-length strings into one length, by padding each string with Spaces on the right. Note that the extra spaces inserted to improve a table's appearance could easily double or triple the size of the table. This increased size not only takes up disk space, but slows processing of table. You must decide whether appearance or size is more important.
```text
Options
justify recognizes the following options:
```
-e Expand the column to the next tab stop. Ordinarily, a column is only as wide as the widest data or column name. This improves the appear, but increases the size of the file.
The following options override the default justifications (left-justify character strings, rightjustify numbers):
-l (This is the letter “el", not the number one.) Left-justify all named columns. -c Center all named columns. r Right justify all named columns.
These options are sticky, meaning that if you follow an 1, c, or r option with several column names, each is treated according to the option. For example, -1 Description Account left justifies both Account and Description, regardless of the data each contains.
-t’c Use the character ¢ as the column separator instead of tab. c can be any ASCII character. Note, however, that once you process a table with this option, you can no longer use /rdb commands on it. because all /rdb commands require tabs as column separators. See the command trim for a discussion of how you can protect special characters from the shell.
*— PDF-Seite 245 · Buchseite 235 —*
Example
One use of justify is to align columns. Variable-length character columns (like names and descriptions) destroy the alignment of columns. For example, notice how the variablelength names cause the tabs to break at different points in the following table:
Name Credit
```text
Anderson 23.49
Ho 145.98
Johnson 1.15
```
One solution is to move the variable length column to the last column: column Credit Name \< credit
```text
The table now appears as follows:
Credit Name
```
```text
23.49 Anderson
145.98 Ho
1.15 Johnson
```
Another solution is to use justify to right-pad the Name column, and (while we're at it) align the floating point number in the Credit:
Name Credit
```text
Anderson 23.49
Ho 145.98
Johnson 1.15
```
Remember that the file is now larger. All of those extra blank spaces can double or triple the size of your file.
It is easier to enter the initial data into a table without the padding characters. Then you can use justify to pretty up the table.
When using the command Iisttotable to convert a list-format file to a table, you may wish to use justify to make the resulting table readable.
```text
See Also
column, compresss, listtotable, trim
```
*— PDF-Seite 246 · Buchseite 236 —*
```text
label — /rdb Command
```
```text
Print mailing labels from a mailing list
label < list
```
The command label prints mailing labels from a mailing list, in list format. This command is obsolete because the command report can make labels more easily; but it is is retained as an example of shell programming.
label is a shell script so you can change it easily to handle different lists and labels.
```text
Example
If you had a file called maillist that looked like this:
```
Number 1
```text
Name Ronald McDonald
Company McDonald’s
Street 123 Mac Attack
City Memphis
```
State TENN
ZIP 30000
Phone (111) 222-3333
Number 2
Name Chiquita Banana
Company United Brands
Street Uno Avenido de la Reforma
```text
City San Jose
State Costa Rica
ZIP 123456789
```
```text
Phone 1234
The command
label < maillist
generates mailing labels that look like this:
```
```text
Ronald McDonald
McDonald’s
```
```text
123 Mac Attack
Memphis, TENN 30000
```
Chiquita Banana
United Brands
Uno Avenido de la Reforma
San Jose, Costa Rica 123456789
```text
See Also
letter, report
```
*— PDF-Seite 247 · Buchseite 237 —*
```text
length — /rdb Command
Return the length of its argument or input file
length [string] [<_file]
```
The command length outputs the number of characters in its first argument. If there is no argument, it reads the standard input.
Because length counts only its first argument, you must put quotation marks around all of the words on the command line to make them one argument.
length uses we -c to do the counting.
```text
Example
Here we find the length of a string and a file.
```
length aAl This returns 3. The next command length ‘word1 word2’ returns 11 — that is, the length of word1 plus word2 plus the space between them. The final example measures the number of characters in file length.1: length \< length.1 Note that you need must quote strings if they have spaces or tabs in them. See Also COHERENT Lexicon: we
```text
letter — /rdb Command
Print form letters from a mailing list
letter letter.1 ... < maillist
```
The command letter prints form letters from a standard letter and a mailing list. It is obsolete, because the command report is so much more powerful and easier to use; but it is retained for compatibility and as an example of shell programming.
letter is a shell script. so you can be easily changed it to handle different lists and letters. To modify it, copy letter from $RDB/bin/letter to your local directory, then use your text editor to edit it. Then you can modify it with a text editor to handle any special features of your mailing list and letters.
```text
Example
If you have a file called maillist that looks like this:
```
*— PDF-Seite 248 · Buchseite 238 —*
```text
Name Ronald McDonald
Company McDonald’s
Street 123 Mac Attack
City Memphis
```
State TENN
ZIP 30000
Phone (111) 222-3333
Name Chiquita Banana
Company United Brands
```text
Street Uno Avenido de la Reforma
city San Jose
```
State Costa Rica
ZIP 123456789
## Phone 1234
Assume, too, that the two parts of your letter are in two files. letter.1 contains: We have a new product that we want to sell to everyone at
And letter.2 contains:
```text
Please have everyone send us an order. We wil? be very grateful.
Sincerely,
```
```text
Mr. Marketing
Makeapile, Inc.
```
To assemble the letter files and the mailing list into one set of mail-merged letters, type the following command:
```text
letter letter.1 letter.2 < maillist
This produces:
```
```text
Ronald McDonald
McDonald‘s
```
```text
123 Mac Attack
Memphis, TENN 30000
Dear Ronald McDonald:
```
```text
We have a new product that we want to sell to everyone at
McDonald’s, Please have everyone send us an order. We will be
very grateful.
```
Sincerely,
```text
Mr. Marketing
Makeapile, Inc.
```
\<... spaces to bottom of letter ... \>
*— PDF-Seite 249 · Buchseite 239 —*
Chiquita Banana
United Brands
Uno Avenido de la Reforma
San Jose, Costa Rica 123456789
Dear Chiquita Banana:
```text
We have a new product that we want to sell to everyone at United
Brands. Please have everyone send us an order. We will be very
grateful.
```
```text
Sincerely,
Mr. Marketing
Makeapile, Inc.
```
\<... spaces to bottom of letter ... \>
The following sample letter program prints out the mailing name and address, and the salutation Dear Name. It then cats letter.1. echos the company name, and finally cats letter.2. letter writes its output to temporary file TMP, then nroffs the TMP file to the standard output. nroff reformats the file (left and right justified) for each company name's length.
By studying the letter shell script and the COHERENT shell’s documentation (sh or ksh), you can assemble fancy, complex form letters. See Also
```text
label, report
COHERENT Lexicon: cat, ksh, nroff, troff, sh
```
```text
like — /rdb Command
Find names that sound like another name
like similar-name file [ name-column ]
```
The command like converts a name to Knuth’s soundex code and looks it up in the .x secondary-index file of a name. To work, you must have first run the command soundex, to create the soundex file.
```text
Example
See soundex for examples.
```
See Also
```text
soundex
```
```text
listtosh — /rdb Command
Convert list format to shell variable
listtosh < list
```
The command listtosh converts a list-format file (column\data) to a shell variable format (VARIABLE='value’). You can use this to move a record into a shell variable.
```text
Example
Consider file maillist:
```
*— PDF-Seite 250 · Buchseite 240 —*
```text
listtotable
```
Number 1
```text
Name Ronald McDonald
Company McDonald’s
Street 123 Mac Attack
City Menphis
```
State TENN
ZIP 30000
Phone (111) 222-3333
Number 2
Name Chiquita Banana
Company United Brands
```text
Street Uno Avenito De La Revolution
City San Jose
```
State Costa Rica
ZIP 123456789
Phone 1234
```text
The command
eval ‘row ‘Number == 2’ < maillist | listtosh’
transforms the mailing list into the following format:
```
```text
Number='2’
```
```text
Name='Chiquita Banana’
Company=’United Brands’
```
```text
Street=’Uno Avenito De La Revolution’
City='San Jose’
```
```text
State='Costa Rica’
```
```text
ZIP='123456789"
```
```text
Phone=‘ 1234’
```
```text
Once this is done, test the transformation by typing:
echo "$Name’s phone number is $Phone."
```
```text
This writes the following on the standard output:
Chiquita Banana’s phone number is 1234,
```
```text
See Also
tabletolist
```
```text
listtotable — /rdb Command
```
```text
Convert from list to table format
listtotable [ -el ] < listfile
```
listtotable converts a file in list format to table format. Some /rdb programs must see files
in table format, so the conversion is necessary.
In addition, table-formatted files are processed faster than list-formatted files. Any time you send a list-formatted file through a pipe of two or more programs, even if they can handle list format, convert them to table format so that the programs in the pipe will run two or
three times faster on average.
*— PDF-Seite 251 · Buchseite 241 —*
The reason that table-formatted files run so much faster is that a list file is often two or three times larger than a table because of the repeated column names. Therefore, when handling list-formatted files. the programs have to process two or three times as many characters.
```text
Options
listtotable recognizes the following options:
```
-e Expand each column to next tab stop. Ordinarily, table columns heads are only as wide as list column heads.
-1\_No head line in the list file. This option makes it possible to convert and sometimes use the older list-formatted files.
Earlier versions of /rdb did not require the leading newline in the list-formatted file; however, this requirement was added by later editions of /rdb to make it easy for its commands to distinguish a list file from a table.
```text
List and Table-Format Rules
List format looks like this:
```
Number 1
```text
Name Ronald McDonald
Company McDonald’s
Street 123 Mac Attack
City Memphis
```
State TENN
ZIP 30000
Phone (111) 222-3333
Number 2
Name Chiquita Banana
Company United Brands
Street Uno Avenido de la Reforma
```text
city San Jose
State Costa Rica
ZIP 123456789
```
Phone 1234
Remember there are three rules for constructing a list-format file:
1. The first character in the file is a newline. Be sure that there are no unseen spaces, tabs, or nonprinting characters on the first line, or things will get quite messed up.
2. Each line consists of two columns separated by a tab. The first column is gives the column's name, and the second column gives its values.
```text
3. A newline character follows each row (record).
And there are three rules for contructing a table, as follows:
1. One tab between each column in a row. and a newline at the end.
```
2. Name ofthe column at the top of the column, in the first line of the file.
*— PDF-Seite 252 · Buchseite 242 —*
```text
lock
```
3. Adash line as the second line in the file.
```text
Example
The command
```
```text
listtotable < maillist
converts list file maillist into table format. The result appears as follows:
Number Name Company Street City State ZIP
```
```text
1 Ronald McDonald McDonald’s 123 Mac Attack Memphis
TENN 30000 (111) 222-3333
```
```text
2 Chiquita Banana United Brands Uno Avenito De La
Revolution San Jose Costa Rica 123456789 1234
```
When you look at this messy table, you can see the need for list format. The information in each column is often too wide for the screen and wraps around to the next line.
```text
See Also
tabletolist
```
Notes If you use this command with a table instead of a list file, you will see a mess.
```text
lock — /rdb Command
```
```text
Lock a record or field of a file
lock filename processid from to indexfrom indexto
```
The command lock locks filename by writing a row into the lock file / tmp/Lfllename, which contains one line for each locked record or field. Its command line contains the following arguments:
```text
processid
The process identifier of the program that locks filename.
```
```text
JSrom The beginning point of the bytes to be locked.
to The end point of the bytes to be locked.
```
```text
indexbegin
The beginning point of the index entry for the data being locked.
```
```text
indexend
The end point of the index entry for the data being locked.
```
When a process attempts to lock a string of bytes that is already locked, lock returns an error condition. You can test for this by using the COHERENT command test to test the shell variable $?.
Example
Let's use lock on table inventory, which appears as follows:
*— PDF-Seite 253 · Buchseite 243 —*
Item Amount Cost Value Description
```text
st 3 50 150 rubber gloves
2 100 5 500 test tubes
```
3 5 80 400 clamps
4 23 19 437 plates
```text
5 99 24 2376 cleaning cloth
6 89 147 13083 bunsen burners
H 5 5 175 875 scales
```
First. use seek to locate the record and return the offset and size, as follows:
```text
LOCATION=‘echo 5 | seek -mb inventory Item‘
echo $LOCATION
207 245 0 8
```
This means that the record is offset 207 bytes into file inventory, and that it is 38 bytes long, ending at byte 245. The O and 8 mean that there is no secondary index file.
```text
Now we can call lock to lock the record:
lock inventory $$ $LOCATION
```
Note that we use the shell variable SLOCATION to supply the arguments from and to. We also use the built-in shell variable $$ to write the process identifier on the command line.
```text
The lock /tmp/Linventory has the following contents:
207 245 0 8
```
See Also
```text
seek, unlock
COHERENT Lexicon: test
```
```text
lowercase — /rdb Command
Transform text to lower case
lowercase [string ...] [< file]
```
The command lowercase converts to lower case every letter in string or file. If there are no arguments, it reads and converts the standard input. It uses tr, the COHERENT charactertranslation command, to do the converting.
Example
```text
The command:
lowercase BIG WORDS
```
```text
prints
big words
```
on the standard output.
```text
If the file CAPITALS contains the string
THESE ARE ALL CAPS.
```
*— PDF-Seite 254 · Buchseite 244 —*
```text
then the command
lowercase < CAPITALS
prints on the standard output:
these are all caps.
```
See Also
```text
cap, uppercase
COHERENT Lexicon: tr
```
*— PDF-Seite 255 · Buchseite 245 —*
```text
maximum — /rdb Command
Display the maximum value in a column
maximum [-1] [column...] < table
```
The command maximum displays the maximum value of each column. If no column appears on the command line, maximum returns the maximum value in every column in table.
The -1 option writes the table to the standard output, as well as the minimum value for each named column. Example
For an example of this command, see the entry for total.
```text
See Also
mean, minimum
```
```text
mean — /rdb Command
Display the mean of a column
mean [-l1] [ column... ] < table
```
mean displays the mean value of each column. If no column appears on the command line, mean returns the mean value for each column in table.
mean assign the value of zero to a blank line. This changes the value of the mean. If that is not what you want, use the command rmblanks or compress -b to remove blank lines. mean also treats blank values as zero
The option -1 prints the contents of the table, as well as the mean value for each named column.
Example
For an example of this command, see the entry for total.
See Also
```text
maximum, minimum
```
```text
menu — /rdb Command
Root menu with some COHERENT commands
menu
```
The command menu displays a table of commands that you can execute by simply typing a number or a name. Menus are useful for inexperienced users. Experienced users can set up a menu very easily.
menu is a shell script that simply echos the menu table of choices, then waits for the user to type a number or name. Then menu uses a shell case statement to execute a command or series of commands for each choice. To set up your own menus, simply copy the menu shell command from the $RDB/bin into your directory, then edit it. You should change its name to Menu or Menu.something, to keep from confusing /rdb.
There is a sample local menu, named Menu in directory SRDB/demo.
*— PDF-Seite 256 · Buchseite 246 —*
```text
Example
The following gives an example menu:
COHERENT MENU
Number Name For
0 exit leave menu or return to higher menu
1 Menu goto another local menu (if any)
2 sh get COHERENT shell
3 vi edit a file
4 mail read mail
5 send send mail to someone
6 cal see your calendar
7 who see who is on the system
8 1s list the files in this directory
9 cat display a file on the screen
10 rdb display rdb commands
Enter a number or name for the action you wish or DEL to exit:
```
menu waits for you to type your choice of number or name. Numbers are quicker to type. but names are more easily remembered. and help you learn how to do things at the shell level.
## Setting Up Your Own Menus
You can automate your operations with menus. If you have naive users who might have trouble learning or remembering the COHERENT or /rdb commands, you can set up menus for them. Also, when you have an operation in which a few commands are repeatedly executed, you can put them into a menu for simple choice.
You can put your menus in the directories in which they will be used or in your SHOME/bin or other bin directory.
To start, go to the directory of your choice and copy the $RDB menu to your directory: cp $RDB/bin/menu Menu
```text
or
cp $RDB/demo/Menu .
```
We suggest the convention of using the name Menu with the capital ‘M' so it appears at the top of your list of files when you do an le command.
You can then name submenus; for example, Menu.other where other is something that suggests the kinds of commands the menu displays.
Now edit the Menu file. As you study the code, you will find that it is very easy to create your own directory.
Menu is in two parts. The first part is the menu table:
*— PDF-Seite 257 · Buchseite 247 —*
```text
cat << SCREEN
```
```text
$CLEAR
Number Name
```
```text
CWOMNINAU SP WNHHO
a
®
3
a
```
”
COHERENT MENU
```text
leave menu or return to higher menu
goto another local menu (if any)
get unix shell
```
```text
edit a file
```
```text
read mail
```
```text
send mail to someone
```
```text
see your calendar
```
```text
see who is on the system
```
```text
list the files in this directory
display a file on the screen
display rdb commands
```
Please enter a number or name for the action you wish or DEL to exit:
SCREEN
The command cat simply sends to the screen everything after the command and before the line that begins with SCREEN, including the line that begins Please enter a number.
The shell replaces $CLEAR on the first line with a sequence of characters that clears the terminal. $CLEAR must have been set by the following command in the menu or in the «profile file of the user:
```text
CLEAR=‘clear’
```
The second part of Menu is a large case statement that you can edit to do what you want.
Here is a sample:
```text
read ANSWER COMMENT
```
```text
case $ANSWER in
```
```text
O|exit)
1|Menu)
2|sh)
3|vi)
```
```text
4|mail)
5| send)
```
```text
exit 0 ;;
Menu ;;
sh 7;
```
```text
echo ‘Which file or files do you wish to edit’
read ANSWER COMMENT
```
```text
vi $ANSWER $COMMENT
```
```text
rr
```
```text
mail ;;
```
```text
echo ‘Please enter login name of person to send mail to’
read ANSWER COMMENT
```
echo ‘Type you letter, and end by typing Ctrl-d’
```text
mail $ANSWER
```
```text
vi
```
*— PDF-Seite 258 · Buchseite 248 —*
```text
6|cal) (cd ; calendar) ;;
?
```
```text
7|who) who ;;
8|1ls) ls 3;
9|cat)
```
```text
echo ‘Please enter the name of the file you wish to see’
read ANSWER COMMENT
cat $ANSWER
vi
10|rdb) menu.rdb ;;
*) echo ‘Sorry, but that number or name is not recognized.’ ;;
esac
```
The command read waits for the user to enter his choice. The first word typed is assigned to the shell variable ANSWER. If the user types any more words, they are assigned to variable COMMENT, which might be used in your commands.
Next is the case statement that examines SANSWER to decide which command to execute. Note that the number and name are separated by a vertical-bar character ‘|’ to mean or: Olexit) exit 0 ;;
This line is selected if type either 0 or exit. The command exit is then executed. The double semicolons “;;" are required to show the end of the commands for this case statement.
Each case statement can hold any command or series of commands that you could type at your terminal. esac at the bottom is case spelled backwards; it marks the end of the whole case statement.
The expression \*) catches any pattern that does not match earlier patterns. In this case, a message is displayed. The pound sign ‘#' marks the beginning of a comment.
You have great power to do things as a result of the user selecting a choice. Of course, you need to match the name and number in your menu table with the patterns in the case statement; it is easy to edit the first part and forget to edit the second.
```text
See Also
COHERENT Lexicon: case, cat, clear, echo, esac, ksh, read, sh
```
```text
minimum — /rdb Command
Display the minimum of each column selected
minimum [ -1] [column...] < table
```
The command minimum returns the lowest value of each column in table. If no column is named on the command line, minimum returns the minimum value for every column in table. Blank lines are given the value of zero.
Option -I returns the contents of table, as well as the minimum value of each column.
Example
For an example of using the command in a script, see the total
```text
See Also
maximum, mean, total
```
*— PDF-Seite 259 · Buchseite 249 —*
```text
not — /rdb Command
Logical not, to reverse return status of command
not command ...
```
The command not converts a return status of zero to 255, and any nonzero return status to zero. Thus, true becomes false and vice versa. This is used to test a command for not true or false.
Example
```text
This example shows how not reverses the return code of the COHERENT command true:
true ; echo $?
```
This command returns zero. On the other hand, the command
```text
not true ; echo $?
```
returns 255.
```text
See Also
COHERENT Lexicon: false, true
```
```text
number — /rdb Command
Insert a column-row number into a table or list
Number < tableorlist
```
The command number creates appends a new column to the beginning of a table, or as the first field in a list. The newly created column contains the number of each row in the table. Unlike the related command Number, number writes the word “number” in lower-case letters as the header on the column.
```text
Example
For example. consider the following table, called inventory:
```
```text
Item# Amount Cost Value Description
a: 3 5.00 15.00 rubber gloves
2 100 0.50 50.00 test tubes
3 5 8.00 40.00 clamps
4 23 1.98 45.54 plates
5 99 2.45 242.55 cleaning cloth
6 89 14.75 1312.75 bunsen burners
7 5 175.00 875.00 scales
```
```text
Typing the command
number < inventory
```
yields the following result:
*— PDF-Seite 260 · Buchseite 250 —*
```text
number Item# Amount Cost Value Description
1 1 3 5.00 15.00 rubber gloves
2 2 100 0.50 50.00 test tubes
3 3 5 8.00 40.00 clamps
4 4 23 1.98 45.54 plates
5 5 99 2.45 242.55 cleaning cloth
6 6 89 14.75 1312.75 bunsen burners
7 rf 5 175.00 875.00 scales
```
Note that the first column is the new number column.
```text
See Also
Number, addcol, column, jointable, rename
```
Notes
To change the name of a column, use the command rename. To move the row-number column to a different position within its table, use the command column. If you want to change the name of the number column to something else, use the command rename.
Number — /rdb Command
```text
Insert a column-row number into a table or list
Number < tableorlist
```
Number creates appends a new column to the beginning of a table, or as the first field in a list. The newly created column contains the number of each row in the table. Unlike the related command number, Number capitalizes the column heading — that is, the name of the command sets the name of the column.
```text
See Also
number
```
Notes
To change the name of a column, use the command rename. To move the row-number column to a different position within its table, use the command column. If you want to change the name of the number column to something else, use the command rename.
*— PDF-Seite 261 · Buchseite 251 —*
```text
pad — /rdb Command
Add extra spaces at end of last column
pad [-number] < tableorlist
```
The command pad adds extra spaces to the end of the last column of each record in tableorlist. number gives the number of spaces to add to the last column. The default is 70.
pad is useful for preparing up a file for updating by the command update. update writes an edited record back into the file in the same place it was taken out. If you add characters while editing the record, it will not fit.
The command replace looks for trailing and leading spaces to trim, to fit the record back. If it does not find enough room, it appends the record to the end of the file. Padding gives each record a fixed number of extra spaces to be trimmed as needed.
The traditional solution is to use fixed-length records and fields. To do this, you can use the command justify to pad the file; but this often increase the file by two or three times. That makes the file much larger, and increases the time needed to process it. pad lets you control how much larger each record will be.
```text
Example
To pad file maillist, type:
```
```text
pad < maillist > tmp
```
```text
To see the results, pipe the results to the command see:
pad < maillist | see
```
The following appears on the standard output:
```text
Number *J1$
```
```text
Name*JRonald McDonald$
```
```text
Company*JMcDonald‘s$
```
Street\*J123 Mac Attacks
```text
City*JMenphis$
```
State\*JTENNS
```text
ZIP*J30000$
```
```text
Phone*J(111) 222-3333 $
$
```
```text
Number *J2$
```
```text
Name*JChachita Banana$
```
```text
Company*JUnited Brands$
```
```text
Street*JUno Avenito De La Revolution$
```
```text
City*JSan Jose$
```
```text
State*JEl Salvadore$
```
```text
ZIP*J123456789$
```
```text
Phone*J1234 $
$
```
Note the dollar signs, which mark the end of the line, are far to the right of the last column, Phone. Those are the 70 extra spaces that have been added; 70 being the default number of spaces. On such a small record, that is probably far too many.
*— PDF-Seite 262 · Buchseite 252 —*
```text
padstring
```
Technical
Note that column Phone already had a value in it. If a value is already in the last column, pad overwrites the spaces. If the value is longer than the number of spaces, pad writes the value but adds no spaces.
We recommend that you have a last column named Comment or Remarks to act as a catchall for both comments and padding.
```text
See Also
justify, replace, see, update
```
```text
padstring — /rdb Command
```
```text
Return string with blanks to fill a field
padstring [-Jlength string
```
The command padstring adds blanks to the end of string to make it the requested length. This command useful for screen and report writing, where you want to line up everything.
The option -length means to left-justify the string in the field, that is, write the padding blanks to the end of string. The option length, without the hyphen, right justifies the string — that is, it adds the spaces to the beginning of string.
Example The first example padstring 10 string displays the string: string Note that the string is right-justified; that is, the spaces were added to the left of string.
Now we can use this in a report form file to make fixed-length fields. An ordinary form has the files to the right of a field, moving all around. For example, the command
```text
report form < mailtable
```
writes the output:
Name : Ronald McDonald Company: McDonald’‘s
Street: 123 Mac Attack
City +: Menphis State : TENN ZIP: 30000
Phone : (111) 222-3333
Name +: Chiquita Banana Company: United Brands
Street: Uno Avenito De La Revolution
City +: San Jose State : Costa Rica ZIP: 123456789
Phone : 1234
This result is rather messy. However, if we edit the file form to include the padstring command, then we will get a fixed form. as follows:
```text
Name : ’!> Company:
Street:
City +: ’!> State : ZIP:
```
```text
Phone :
```
*— PDF-Seite 263 · Buchseite 253 —*
Now, running report on this file yields:
Name : Ronald McDonald Company: McDonald’s
Street: 123 Mac Attack
```text
City +: Menphis State +: TENN ZIP: 30000
Phone : (111) 222-3333
```
Name : Chiquita Banana Company: United Brands
Street: Uno Avenito De La Revolution
```text
City +: San Jose State : Costa Rica ZIP: 123456789
Phone : 1234
```
Note that State has not been done yet, and therefore ZIP moves back and forth; but Company and State stay lined up correctly.
Note that if padstring is too long a name, use the COHERENT link command In to link it to a shorter name. See Also
```text
report, screen
COHERENT Lexicon: In
```
```text
paste.rdb — /rdb Command
Paste together two or more tables
paste.rdb table! table2 ...
```
The command paste.rdb displays table1, table2, and so on, side by side. This is almost identical to the COHERENT command paste.
The /rdb version of paste.rdb uses the COHERENT command pr to list the tables side by side:
```text
pr -m -t -s tablel table2 [...]
```
paste.rdb differs from the command jointable in that jointable looks for matching values in key columns and writes only the rows in which it finds a match. paste.rdb does not care what it is pasting together. You can get some interesting garbage with paste.rdb.
You can also do a kind of visual diff in which you can see an old and new file lined up side by side. You could do this with two list files. but be careful, because the output will generally not be acceptable by other /rdb programs.
```text
Example
The following commands break the table inventory:
```
```text
column Item Value < inventory > tmpl
column Cost Amount Description < inventory > tmp2
```
This yields table tmp1
*— PDF-Seite 264 · Buchseite 254 —*
Cost Amount Description
```text
50 3. rubber gloves
5 100 test tubes
```
80 5 clamps
19 23 plates
24 99 cleaning cloth
147 89 bunsen burners
175 5 scales
```text
Now, you can use paste.rdb to put them back together:
paste.rdb tmpl tmp2
This writes the following onto the standard output:
```
Item Value Cost Amount Description
```text
1 150 50 3 rubber gloves
2 500 5 100 test tubes
```
3 400 80 5 clamps
4 437 19 23 plates
```text
5 2376 24 99 cleaning cloth
6 13083 147 89 bunsen burners
7 875 175 5 scales
```
This is not an efficient way use column; one command could do the job, instead of two. paste.rdb, however, it is a good way to put tables together if jointable is inappropriate. If you had wanted to use jointable here, you should project column Item into both tables. See Also
```text
column, jointable
```
COHERENT Lexicon: diff, paste, pr
Notes
This command is named paste.rdb rather than paste, as in other implementations of /rdb, to avoid clashing with the COHERENT command paste.
*— PDF-Seite 265 · Buchseite 255 —*
```text
path — /rdb Command
Find the full path of a command
path [ command ... ]
```
The command path finds the directory path to a command, if it is in one of the directories in your shell's PATH environment variable.
A path means two things in COHERENT:
1. It means the list of nested directories within which a file is located. For example. file FOO may have the path of /usr/local/src/; this means that FOO is kept in directory sre, which in turn is in directory local, which in turn is in directory usr, which in turn is in directory /.
2. It means a list of directories that the shell searches to find an executable program that matches the command typed in. Each user has his path stored in the environmental variable PATH; to see your path, type the command:
```text
echo $PATH
```
path searches the directories named in your PATH to find the path of command. If path cannot find command or if command is not executable, it returns nothing.
```text
Example
If you type:
path column
If this command returns
/usr/rdb/bin
then column lives in directory: /usr/rdb/bin.
```
Please note that for path to work, you must insert into your PATH the directory that holds the /rdb commands.
See Also
COHERENT Lexicon: PATH, .profile
```text
precision — /rdb Command
```
```text
Display the precision of a column
precision [ -1] [column...] < table
```
The command precision returns the maximum number of digits to the right of the decimal point in each column. If no column is named on the command line, precision returns information on every numeric column in table.
The option -1 tells precision to return the entire table, in addition to the precision of each column.
```text
Example
For example of this command, see the entry for total.
```
*— PDF-Seite 266 · Buchseite 256 —*
```text
project — /rdb Command
```
```text
Write selected projects (same as column)
project [ column... ] < tableorlist
```
The command project is another name for the command column.
```text
See Also
column
```
```text
prompt — /rdb Command
Echo a string on the standard output
prompt string ...
```
The command prompt echoes a string onto the standard output. It resembles the COHERENT command echo, but it does not write a newline character after the echoed string. Thus, you can use prompt to write a prompt onto the screen.
Example
The command
```text
prompt "Please enter your name:
writes the following on the standard output:
Please enter your name: _
```
The underscore character marks where this command leaves the cursor.
See Also
```text
chr
COHERENT Lexicon: echo
```
Notes
prompt looks for an environmental variable called ECHONOCR. If the variable is missing or not equal to -n, then prompt calles the COHERENT command echo with its -n option. which drops the newline. If ECHONOCR is set to anything other than -n, then prompt calls \\c option, which is used by some UNIX systems. When using /rdb under the COHERENT system, it is best just to not set ECHONOCR.
*— PDF-Seite 267 · Buchseite 257 —*
R
```text
tdb — /rdb Command
```
```text
List all /rdb programs in directory SRDB/bin
rdb
```
The command rdb prints on the standard output all commands in directory $RDB/bin. This command is a shell script. which you should edit if its output is not to your liking.
```text
See Also
act, helpme, whatis, whatwill
```
```text
record — /rdb Command
Find and output a record from a table
record number < table
```
The command record searches through table for the record with the serial number number. If it finds the record, it prints it and the table's header on the standard output.
Example
```text
To retrieve the third record from table inventory, type:
record 3 < inventory
```
You will see something like the following:
Item Amount Cost Value Description
3 5 80 400 clamps
The following shell script uses record and read to find specific values in table inventory. The command read uses the head line of inventory to assign values to each column name.
```text
: describe - gives the description for an item in inventory
USAGE='usage: describe Item < table’
```
```text
record $1 < inventory |
( read HEAD
read DASH
read $HEAD
echo "Item $Item is $Description"
)
When you type
```
```text
describe 1 < inventory
you see output in the following format:
```
Item 1 is rubber gloves
See Also
```text
row, search
COHERENT Lexicon: read
```
*— PDF-Seite 268 · Buchseite 258 —*
```text
rename — /rdb Command
Rename a column
```
rename [ oldcolumn newcolumn ... ] \< tableorlist
The command rename changes the name of oldcolumn to newcolumn within tableorlist. You can name on the command line as many oldcolumn/newcolumn pairs as you wish.
Example
Consider the table inventory:
```text
Item# Amount Cost Value
1 3 5.00 15.00
2 100 0.50 50.00
3 5 8.00 40.00
4 23 1.98 45.54
5 99 2.45 242.55
6 89 14.75 1312.75
7 5 175.00 875.00
```
The command
```text
Description
rubber gloves
test tubes
clamps
```
```text
plates
cleaning cloth
bunsen burners
scales
```
rename Amount Qty Description Name \< inventory
renames Amount to Qty. and Description to Name. The table now appears as follows:
```text
Item# Qty Cost Value
1 3 5.00 15.00
2 100 0.50 50.00
3 5 8.00 40.00
4 23 1,98 45.54
5 $9 2.45 242.55
6 89 14.75 1312.75
7 5 175.00 875.00
```
```text
If you have a list-formatted file, you
consider the list maillist:
```
Number 1
```text
Name Ronald McDonald
Company McDonald’s
Street 123 Mac Attack
city Memphis
```
State TENN
ZIP 30000
Phone (111) 222-3333
Name
```text
rubber gloves
test tubes
clamps
```
```text
plates
cleaning cloth
bunsen burners
scales
```
can also rename the column names. For example.
*— PDF-Seite 269 · Buchseite 259 —*
Number 2
Name Chiquita Banana
Company United Brands
```text
Street Uno Avenido de la Reforma
city San Jose
```
State Costa Rica
ZIP 123456789
Phone 1234
```text
The command
rename Number Num ZIP Zip < maillist
changes Number to Num, and ZIP to Zip. The list now appears as follows:
```
Num 1
```text
Name Ronald McDonald
Company McDonald's
Street 123 Mac Attack
city Memphis
```
State TENN
Zip 30000
Phone (111) 222-3333
Num 2
Name Chiquita Banana
Company United Brands
Street Uno Avenido de la Reforma
```text
city San Jose
State Costa Rica
Zip 123456789
Phone 1234
```
See Also
```text
column
```
```text
replace — /rdb Command
Insert a record into a file at specified location
replace [-a] [-m[bhirs] tableorlist from to [xfrom xto] < intableorlist
```
The command replace replaces the row at offsets from through fo in tableorlist with the contents of intableorlist. replace will not insert a record larger than fo minus from. It adds spaces to the last column of records within tableorlist that are smaller than the input record.
xfrom and xto give the beginning and end of the offsets of the index entry within tableorlist's associated fast-access table, should there be one.
To obtain painlessly the offsets of the record and its index entry, use the command seek. This is demonstrated in the following example.
The command update remembers the location and size of the record it takes out of a file and passes it to replace so that only a correctly sized file goes back into that file.
*— PDF-Seite 270 · Buchseite 260 —*
```text
replace
```
Options
replace recognizes the following options:
-a Do not append the record in intableorlist to the end of tableorlist. The default to append if the record is too big to fit back into the location from which it was taken. This option allows you to prevent appending. If you want a binary file to stay sorted, you will either have to resort it or not allow appending.
```text
-m{bhirs]
Fast access methods. See the manual page for index for a description of what each
of these options means.
```
Example If table recordtable contains one record, you use can insert that record into table bigfile with the following command:
replace bigfile 1421 1487 0 8 \< recordtable Note that the contents of recordtable replace rows 1421 through 1487 within bigfile. For the second example, consider again table inventory, as follows:
Item Amount Cost Value Description
```text
1 3 50 150 rubber gloves
2 100 5 500 test tubes
```
3 5 80 400 clamps
4 23 19 437 plates
```text
5 99 24 2376 cleaning cloth
6 89 147 13083 bunsen burners
7 5 175 875 scales
```
First, let's use the command seek to extract a record, and save its offset in the shell variable LOCATION:
```text
LOCATION=‘echo 5 | seek -mr -o tmpfile inventory Item’
SLOCATION is initialized to the following
```
```text
207 245 54 62
and tmpfile contains the following:
Item Amount Cost Value Description
```
```text
S 99 24 2376 cleaning cloth
Here we use the record fast-access method.
Now let's change 99 to 199 within tmpfile. so we can see a change:
Item Amount Cost Value Description
```
```text
5 199 24 2376 cleaning cloth
Now we can replace the edited record in inventory:
replace -mr inventory $LOCATION < tmpfile
```
*— PDF-Seite 271 · Buchseite 261 —*
inventory now appears as follows:
```text
Item Amount Cost Value Description
1 3 50 150 rubber gloves
2 100 5 500 test tubes
3 5 80 400 clamps
4 23 19 437 plates
5 199 24 2376 cleaning cloth
6 89 147 13083 bunsen burners
7 5 175 875 scales
You can see that row 5 has been updated, because it now has 199 in it.
See Also
seek, update
```
```text
report — /rdb Command
Write reports using a form and a table
report form < tableorlist
```
The command report produces reports, form letters, mailing labels, invoices, and so forth, for each row in tableorlist, following the template within file form.
You must use a text editor to fill out form to determine how the form will appear. Insert column names from tableorlist between angle brackets (\< \>) where you want the data to appear within the report.
You can even call shell commands from within a form, pass them data from tableorlist, print their output within your formatted form. This is a powerful extension to COHERENT shell programming. report mostly replaces the older commands label and letter. These commands are still part of /rdb, in part for compatibility with older versions, and in part as examples of shell programming.
```text
Form Syntax
The following describes the format of a form:
```
```text
regular text
form prints any characters in your form that do not match the symbols shown
below.
```
\ Angle brackets indicate that data from column-name in the current row of tableorlist should be inserted in place of the column name.
```text
Angle brackets and exclamation points indicate that the shell is to execute
command. Any output from command appears at this point in the report.
```
```text
!>
This is an insertion within a command. The data from column col in the current
row of tableorlist are passed to cmd. This passes the contents of col as an argument
to command. The output of command then replaces this entry within the form.
```
If report does not recognize a column name, it prints \ as if it were normal text. This allows you to use the angle brackets as literal characters within your form. if you
*— PDF-Seite 272 · Buchseite 262 —*
wish. It also helps you debug your form: if the data from the table are not replacing \, then column-name does not exactly match the column name in the table. Check for spelling errors, upper- and lower-case discrepancies, embedded blanks, and nonprinting characters.
```text
Example
Consider table maillist, as follows:
```
```text
Name Ronald McDonald
Company McDonald’s
Street 123 Mac Attack
city Memphis
```
State TENN
ZIP 30000
Phone (111) 222-3333
Name Chiquita Banana
Company United Brands
```text
Street Uno Avenido de la Reforma
City San Jose
```
State Costa Rica
ZIP 123456789
Phone 1234
You could use an editor to develop a form like the following:
```text
```
```text
```
```text
```
```text
< City >,
```
```text
Hi < Name >:
The date and time is
We are also sending this letter to:
```
```text
"’ | justify 1!>
Bye !>
```
Note that we have used all three types of inserts: column name, command, and command insert. Now with these two files ready, you only need type
```text
report form < maillist
```
to see the following output:
*— PDF-Seite 273 · Buchseite 263 —*
```text
reportwriter
```
Ronald McDonald
McDonald's
123 Mac Attack
Memphis, TENN 30000
Hi Ronald McDonald:
The date and time is Wed Aug 19 01:58:19 PST 1983
We are also sending this letter to:
Chiquita Banana San Jose
Bye Ronald McDonald
Chiquita Banana
United Brands
Uno Avenido de la Reforma
San Jose, Costa Rica 123456789
```text
Hi Chiquita Banana:
The date and time is Wed Aug 19 01:58:40 PST 1983
```
We are also sending this letter to:
Ronald McDonald Memphis
Bye Chiquita Banana
```text
```
See Also
```text
label, letter
COHERENT Lexicon: echo
```
```text
reportwriter — /rdb Command
Sample program to write standard reports
reportwriter
```
Some users have noted that the shell escape places an extra line in the output. If you don't want the extra line say something like:
The command reportwriter is a sample shell program that writes a sample standard report. It uses the command splittable to divide a table into page-sized tables. It shows several tricks for using COHERENT shell programming and /rdb tools to put together reports.
*— PDF-Seite 274 · Buchseite 264 —*
Example Here is what reportwriter produces (with the middle of each page replaced with an ellipsis to keep the listing short):
```text
Prices of Computers that ran UNIX(TM) in 1983
From Urban Software of New York City
Report Date: 9 Feb 1985
```
```text
Price Company City
Advanced Micro Devices Santa Clara
Alcyon Corporation San Diego
American Telephone & Telegraph
BASIS Microcomputer GmbH D-4400 Muenster
Corvus Systems San Jose
David Computers Inc. Kitchener
Digital Computers Ltd. Tokyo 102
Heurikon Corp. Madison
```
```text
Western Digital Irvine
Western Electric Corp.
```
```text
4.2 Venturcom/IBM PC Cambridge
13.9 Victory Computer Systems, Inc. San Jose
Page 1
See Also
splittable
```
```text
rmblank — /rdb Command
Remove blank rows from a table
rmblank < table
```
The command rmblank deletes from table all input rows that consist of only white space (spaces and tabs). The related programs delete and replace blank out records. They can be used in transaction processing where the files are too large to process and several users are updating them. At a quiet time, the files can be compacted and reindexed.
Be sure to reindex any file that is processed by either rmblank or compress.
Example
First we have table inventory, as follows:
*— PDF-Seite 275 · Buchseite 265 —*
```text
Item Amount Cost Value Description
1 3 50 150 rubber gloves
2 100 5 500 test tubes
3 5 80 400 clamps
4 23 19 437 plates
5 99 24 2376 cleaning cloth
6 89 147 13083 bunsen burners
7 5 175 875 scales
```
Then we delete record 4
```text
echo 4 | delete inventory Item
```
and inventory now appears as follows:
```text
Item Amount Cost Value Description
1 3 50 150 rubber gloves
2 100 5 500 test tubes
3 - 80 400 clamps
5 99 24 2376 cleaning cloth
6 89 147 13083 bunsen burners
vf 5 175 875 scales
```
The command see shows the contents of inventory actually to be as follows:
```text
Item*IAmount*ICost“IValue*IDescription $
----“[------ “I ---- “I -----* I-------------= $
1*z 3°I 50*I 150*Irubber gloves$
2°1 100° 5°I 500*Itest tubes$
3°I 5*I 80°I 400*Iclamps$
nf “I “I “I $
ax 99°I 24*I 2376*Icleaning cloth$
“Tt 89*I 147°113083*Ibunsen burners$
t: 5°I 175*I 875*Iscales$
```
```text
yaw
```
A
```text
Now the command
rmblank < inventory
```
removes lines that consist only of blanks. After we run this command, inventory appears as follows:
Item Amount Cost Value Description
```text
1 3 50 rubber gloves
2 100 5 test tubes
```
3 5 80 clamps
```text
5 99 24 cleaning cloth
6 89 147 13083 bunsen burners
7 5 175 875 scales
```
*— PDF-Seite 276 · Buchseite 266 —*
Remember to reindex a file after you run rmblank on it.
```text
See Also
compress, delete, index, replace, rmblank
```
```text
rmcore — /rdb Command
Remove all core files
rmcore
```
The command rmcore uses the COHERENT system's command find to search for files named core in the current directory and all subordinate directories. As its name implies, it removes all such files that it finds.
Run this command first when you begin to fill up your disk. rmcore starts at the directory you are in and goes down the file tree. If you are superuser, you can issue this command at the root directory \*/'‘ and clean the whole system.
```text
See Also
COHERENT Lexicon: core, find, rm
```
```text
row — /rdb Command
Make a new table where rows match logical condition
row ‘column condition column-or-value ..* < table
```
The command row creates a new table from table. The new table consists of only those rows that meet condition.
row uses a script written in the awk language. which gives you great power for specifying the logical condition.
Several conditional expressions can be combined with the logical AND (&&) and OR (| |) operators. Because the logical conditions are represented by special characters, they must be enclosed by apostrophes, to protect them from being interpreted by the shell. If you have special characters within a column name, enclose the column name in quotation marks.
```text
Example
First a simple example. Consider table inventory
```
Item Onhand Cost Value Description
```text
1 3 5 15 rubber gloves
2 100 1 100 test tubes
```
3 5 8 40 clamps
4 23 2 51 plates
```text
5 99 2 97 cleaning cloth
6 89 18 1602 bunsen burners
7 5 175 875 scales
```
```text
To make a table of all of the parts that cost more that $5. type:
row ‘Cost > 5’ < inventory
```
The new table appears as follows:
*— PDF-Seite 277 · Buchseite 267 —*
Item Onhand Cost Value Description
3 5 8 40 clamps
```text
6 89 18 1602 bunsen burners
7 , 5 175 875 scales
```
Now a more complex example. If you want a table of all the burners and of all of the items of which we have fewer than ten in stock, type:
row ‘Description ~ /burner/ || Onhand \< 10’ \< inventory
The new table appears as follows:
Item Onhand Cost Value Description
```text
1 3 5 15 rubber gloves
3 5 8 40 clamps
```
```text
6 89 18 1602 bunsen burners
7 5 175 875 scales
```
The string ~ /burner/ searches for the string “burner” anywhere in the column. The double pipe (| |) means logical OR.
## Column Names
The commands row, compute, and validate recognize column names as upper- and lowercase letters, digits, and the underscore ‘\_'. The regular expression is [A-Za-z0-9\_]. If you have any other characters in your column names, put apostrophes or quotation marks around them.
row compares the recognized strings with the table’s head line. Only if it finds a match does it convert the string to the $1, $2... column positions that awk needs.
```text
awk’s Reserved Words
```
awk is the pattern-scanning language that does all of the work for the commands row, compute, and validate.
awk recognizes the following words as having special significance. If you name a columns with any of these reserved words and then try to use them in a query, the /rdb commands that are built around awk turn them into column positions and awk does not see them. It is best to avoid these names as column heads or simply capitalize the first letter of each of your column names.
This list also indicates the many functions you have with awk. However. do not rely on the following descriptions. The tutorial section of your COHERENT manual contains a summary of the awk language.
Please note that this list of awk functions and reserved words comes from UNIX System V. Other implementations of awk may not contain all of these functions.
*— PDF-Seite 278 · Buchseite 268 —*
```text
Reserved Word Description
BEGIN.... -Pattern that matches before first input record
END .... .. Pattern that matches after last input record
break .. ..Exit the nearest for or while loop
continue... ...Go to next iteration of for or while loop
```
```text
else.. Used in if then else expression
```
.. Leave program entirely, as if at end of input
.. Raise number to a power
```text
..for (expression ; condition; expression)
```
..Get next input line
```text
..df (condition) statement [else statement]
```
```text
..for (variable in array) statement
```
.-dndex ( string1, string2 )
..Truncate argument to integer
```text
-.Return current line length, or length of argument
.- Return log (to base 2) of argument
```
```text
.. Skip to next record and reexecute all commands
. Output variables
```
.-printf ("format", variable, ... )
.- Split (string, arrayname, separator)
.. Sprintf ("format", variable, ... )
.. Return square root of argument
```text
substr ( string, start, number )
```
. while ( condition ) statement
Although row is built around the awk language. row has the advantage of knowing about the names of the columns. Therefore, you can use column names instead of column positional numbers. To grasp the full power of row and compute. read the COHERENT manual's tutorial on awk.
See Also
```text
compute, row, select, validate
COHERENT Tutorials: Introduction to the awk Language
```
*— PDF-Seite 279 · Buchseite 269 —*
Ss
```text
sale — /act/sales Command
Enter sale order, and item, update customer
sale
```
The command sale is part of the accounting/sales system included with /rdb. It enters a sales order into table saleorder and items into table saleitem. It also permits an order-taker to add a new customer to the customer-information table customer, or to update information on an existing customer.
Example
sale is interactive, to allow you to confirm each action. First, it asks for customer number. If you give it a number, it looks the number up in table customer. If it finds a customer with that number, it displays information on that customer for you to confirm. If you do not have the customer's number, you can search with the slash string option or enter the question mark to enter customer. There, you can search for the customer or add a new customer.
The following gives an example order-entry session:
MakeaPile, Inc. saleorder
```text
Enter Customer Number (? for new, /string search, Return to exit) 1
Vendor Number 1
```
Mr. Luke Skywalker CEO
```text
Rebel Enterprises
123 Lea Street
Space Port City, Far Side 123456789 Tatooy
```
```text
rdb 1
```
```text
Order Number Code Backord Qty Price Total Name
1 1 rdb 10 1 1500 1500.00 /rdb
Number Cust Date Shipped Gross Tax Total
```
Ft 2 850723 0 1500.00 75.00 1575.00
Is this correct? (y, n) y After you have confirmed the order, table sale modifies table salesorder, as follows:
Number Cust Date Shipped Gross Tax Total
1 2 850723 860525 1500.00 75.00 1575.00
2 2 850724 860525 3000.00 150.00 3150.00
```text
3 3 850902 860525 22500.00 1125.00 23625.00
4 3 850902 0 36000.00 1800.00 37800.00
5 3 850902 0 21000.00 1050.00 22050.00
```
It also modifies table salesitem, as follows:
*— PDF-Seite 280 · Buchseite 270 —*
```text
schema
```
Order Number Code Backord Qty Price Total Name
```text
1 L rdb 10 1 1500 1500.00 /rdb
2 1 rdb 10 2 1500 3000.00 /rdb
3 1 rdb 10 5 1500 7500.00 /rdb
3 2 act 10 10 1500 15000.00 /act
4 1 rdb 105 1500 7500.00 /rdb
4 2 rdb 10 19 1500 28500.00 /rdb
5 1 rdb 10 5 1500 7500.00 /rdb
5 2 act 10 9 1500 13500.00 /act
```
Once you enter the correct customer number, sale gives you a table of items to enter. Type in Code and Qty, and the program looks up the other information in the inventory. Verify that the information is correct and make sure that you have enough in inventory to satisfy the order. Continue entering items until you are through. Pressing \ indicates that you are finished; sale then calculates the totals for the order, including tax.
This program uses the commands cursor and termput to maneuver about the screen.
```text
See Also
cursor, invoice, postar, termput
```
```text
schema — /rdb Command
```
```text
Print a table’s schema
schema tableorlist ...
```
The command schema prints the schema, or a data-base dictionary, for each tableorlist.
Other data-base systems require that you define a schema prior to creating a table. In /rdb, you can derive a schema from an existing table or tables.
Example
The following command combines the schemas for tables inventory and maillist. The example pipes the concatenated schema through the command justify to “pretty up” the output:
```text
schema inventory maillist | justify
```
This produces the following:
*— PDF-Seite 281 · Buchseite 271 —*
Table Field Name inventory 1 Item inventory 2 Amount inventory 3 Cost inventory 4 Value inventory 5 Description maillist x Number maillist 2 Name maillist 3 Company maillist 4 Street maillist 5 city maillist 6 State maillist ae ZIP maillist 8 Phone Because schema is a shell script. you can modify it to give widths of columns, data types, and so on.
See Also
```text
datatype, precision, width
```
```text
screen — /rdb Command
Convert a form into a screen-input shell program
screen