man page(1) manual page
Table of Contents


nxqddb - Generic Tcl/Tk/Fx (Tk 4.X) interface to qddb databases.


nxqddb RelationName


nxqddb reads the schema for RelationName and uses the QDDBDIRS environment variable to find it. The format of the QDDBDIRS environment variable is:


The main screen in nxqddb(1) has a row of menubuttons at the top and a scrollable canvas containing entry boxes for each attribute. A general search box is located above the attributes' canvas and queries in this field are not attribute-specific. Attribute-specific queries (such as Name == "Eric Herrin") should be entered in the attributes' entry fields. A query may be initiated by either invoking the Search menu item (under the Edit menubutton) or by pressing <Return> in any field.

All menu buttons have accelerators defined as <Alt>-c, where c is the underlined character in the menu button. Any menu item under a menu button may be selected by bringing up the menu and typing the underlined character. For example, to invoke the Clear function you would press <Alt-e> C.

There are 4 modes in nxqddb(1). The default mode is called Search Mode. In search mode, you may enter values in any attribute field and/or the general search field. The result is the intersection of all tuples that match each given value. When a query is complete, a listbox will appear detailing the tuples that matched the query. If only one tuple matched the query (and the search configuration doesn't specify fields that produce multiple rows), then the tuple is immediately brought into Change Mode. If multiple tuples matched the query, the listbox will contain all unique rows for each tuple that matched the query and the values are specified by the current search results configuration. If another application has the selected tuple locked, then you are placed into Read-only Mode. In Read-only Mode, you may not save the tuple, but you may modify it and save it as a template. Up and down arrow keys may be used to move the selection over the entries in the listbox. A Button-1 mouse press, <Return>, or clicking on the Select button will select the entry to be brought into change mode. Add Mode is selected by Button-1 on the Modes menu button, then click on Add Mode.

Note: Qddb requires an operating system that supports fcntl-style record locking. nxqddb will fail if you attempt to run it over NFS without a lockd, for example.


Entry boxes have some standard Emacs-style key bindings:

: Goto next entry box <Shift-Tab>: Goto previous entry box <Control-a>: Goto beginning of line <Control-b>: Back one char <Control-d>: Delete current character <Control-e>: Goto end of line <Control-f>: Forward one char <Control-h>: Back one char, delete current char <Control-k>: Kill to end of line, place in cut buffer <Control-n>: Goto next entry box <Control-p>: Goto previous entry box <Control-w>: Delete current selection, place in cut buffer <Control-y>: Yank (paste) cut buffer to current cursor position
: Copy current selection into cut buffer <Button-3> : Paste current selection at current cursor position
: Search in search mode, same as <Tab> otherwise
: Goto next entry box
: Goto previous entry box
: Forward one char
: Back one char

Most listboxes have the standard TK bindings, plus <Up> and <Down> arrow keys. Text boxes have the standard entry except:

: Goto next line <Control-n>: Next line <Control-p>: Previous line <Control-o>: Open current line
: Next line
: Previous line <B2-Motion>: Scroll text

Radiobuttons have the standard <space>, <Return>, and <Button-1> bindings for setting the radiobutton's value. <Shift-space>, <Shift-Return> and <Button-3> undo a radiobutton's setting.


nxqddb allows near-arbitrary search patterns to be specified. All searches are case insensitive. Search patterns may be specified in any attribute field and/or in the generic "Search for" field. The resulting query is the logical intersection of the individual queries in each field including the generic "Search for" field. Each field must contain a valid TCL list consisting of atoms and operators. A valid TCL list consists of white space separated words, possibly grouped together with curly braces ({}). Atoms may be any of the following:
word range:
[a-z0-9]-[a-z0-9] numeric range: number-number
date range:
integer or real number
any V8 regular expression Automatic search-type determination is performed as follows. First, nxqddb checks for a "-" in the string and checks the string types on either end. If both strings appear to be either a word, number, or date, then the appropriate range searching method is used. Next, nxqddb attempts to match the string as a word, number or date respectively. If that fails, nxqddb defaults to regexp. Regular expressions are matched only against full words, so the regular expression a.*b will not match the word carbine but will match the word a123b.

Intersection, union and binary exclusion are supported by nxqddb. If the TCL list (or sub-list) contains three elements (atom operator atom), then both atoms are evaluated and the binary operation is performed on the two atoms in their specified order. If the TCL list contains more than three elements or there is no operator, nxqddb evaluates the expression from left to right, treating spaces as intersection, commas (",") as union and bang ("!") as exclusion. Exclusion is a binary operation where the expression "a ! b" means all tuples that match expression "a" that do not match expression "b". Commas and bangs must be separated by spaces. The key to learning the syntax is knowing that all expressions must be a valid TCL list.


Search for all records with either the words "eric herrin" or the words "raphael finkel" in any fields. {eric herrin} , {raphael finkel}
Search for all records with the words "herrin" or "herron" but not the word "eric."
{herrin , herron} ! {eric}
Search for all records with "eric" and "herrin", then perform a union with all records containing the word "raphael", then an intersection with all records containing the word "finkel."
{eric herrin , raphael finkel}
Search for all tuples matching the regular expression (.*)abc(.*), or containing the words "special customer," but do not contain the word "delinquent." Merge that result with all tuples containing words ranging from "ba" through "bz."
{{(.*)abc(.*) , {special customer}} ! delinquent} , ba-bz Search for all records containing either a date from January 1, 1994 through June 1, 1994, or or from January 1, 1995 through June 1, 1995 (note: dates and date ranges only work in fields marked as type date. 1/1/94-6/1/94 , 1/1/95-6/1/95

Search notes

Date ranges are useless unless you use the type specifier "type date" on some attribute(s) in the Schema file. Specifying a date search in the generic search field, or in a field that is not "type date" will be read as regular expressions.

Make sure to put spaces between atoms and operators. A query of the form:
{ {Joe Blow},{Henry Blow} }
will give you an error message, but something like { joe, blow }
will assume that you want a regular expression "joe," intersected with "blow".

Avoid unpruned regular expressions such as (.*) unless you want to wait a while. This is especially true for large (20-30MB or more) databases.


The expert search form allows you to specify a fully parenthesized expression. The form may be viewed as a tree, where leaf nodes are simple queries (possibly attributed and confined to a particular type of search) and intermediate nodes are logical operations. Each leaf may be configured by selecting the Down arrow button next to the leaf's value(s). You can append a node to any level in the tree by selecting the Append button. You can expand any leaf into an intermediate node and two children with the "Expand node" button (available by selecting the Down arrow button.) You can delete any node with the "Delete" button. Comments entered in the text box at the bottom of the window are retained if you save the search contents to a file.

Leaves that are constrained to a particular search type may provide search data in any form acceptable by the search engine. For example, a date in the form "today -1 year" is acceptable by the search engine, but the simple search will parse it as three words. If you specify "date range" as the search type, then "today -1 year" will be treated as a date.


You can always save your changes and additions to disk by selecting the "Save" button in the menubar. nxqddb(1) also gives you the option of saving your changes away separately, in a template. A template is an ASCII file containing the readable form of a tuple. You may save values to a template in either Search Mode, Change Mode, or Add Mode. You may only read the values from a template in Search Mode or Add Mode. If you want to save some changes and return to them later without affecting the database, you can view them in Add Mode and discard them when you are finished. If you want to use those values, you can first delete the original tuple, then add a new one inserting the template. Templates are accessed via the "Templates" menu button.


nxqddb provides you with a fairly nice set of configuration options. You can set the type of the entry box in the main window to either Entry, Text, or Radiobutton, and set the size of the boxes. nxqddb restricts you to a single width for all entries because it is a generic interface, and our current method of displaying the view generically is in a single column. However, the overall column width can be configured by choosing the Entry Widths cascading menu from the Configure menu button. If you want checkbuttons, formatted screens, or other niceties, you can design your own custom interface with Qddb's Fx Toolkit (see Fx(n)).

Listbox configuration

You may configure both the search results listbox and all instance view listboxes. The search results listbox is capable of listing any attribute. You can configure the search results by selecting "Configure" from the menubar, then "Search Results". The instance view listboxes are capable of listing only those attributes that are children of an expandable attribute. You can get an instance view configuration window with <Control-Button-3> over the attribute's label. Alternatively, you can use <Control-3> while the focus is on any Add, View, or Del button or in an attribute's entry.

Widths for fields in the listbox may be specified in the configuration screen. The listbox configuration specifies (1) the sorting order, (2) ascending/descending, (3) attributes to print, (4) field widths, (5) justification, and (6) field separators. A field width of 0 means unlimited.

The selected attributes form a set of logical rows in the listbox. For example, you might have a student database with the following schema:
Student (Name Address)
Semester ( When Course (Name Grade) * ) * In this case you could review all of a students grades by selecting the attributes Semester.When, Semester.Course.Name and Semester.Course.Grade for the Semester instance listbox. To view only semesters, you would select only Semester.Course.When. To review a student's courses for a semester (not grades), you would select only Semester.Course.Name for the Semester.Course instances. Since only Semester and Semester.Course are expandable, they are the only attributes that allow new instances and have instance listboxes.

By default, when a listbox appears, the first element selected will destroy the listbox and bring the selected instance (or tuple) into view. The Pin checkbutton pins the listbox until the close button is pressed. While a listbox is pinned, you may select instances, review them, and edit them.

Configuring search results and instance views

When configuring the search results from the Configure menubutton, you may select the attributes to show, their width, separators between columns, how to sort those attributes (Sort), and the order in which to show them (Print). The default width is 0 (unlimited).

Instance views may be configured by pressing <Control-Button-3> over an expandable attribute's label. A listbox similar to the search results listbox will appear.

Configuring the entries

The entries can be configured by pressing <Control-Button-3> over the leaf attribute's blue label. A dialog will appear, allowing you to set the type of entry (Entry, Text, Radiobutton), width, height, default values, plus mandatory and read-only properties.


You may save your configuration by selecting the Configure menu and then select one of the Personal, Global, or Default menu items. From any of these menu items, you may then select the Save option. The Personal and Global configurations save not only the listbox configuration, but window placement and other state as well. The Default configuration defines fonts, colors, and other database independent options into a file in your home directory called .qddb_fxrc; each time you start nxqddb(1) or any Fx-based application, it reads these defaults. Personal and Global configurations can only be saved on a per-relation basis and the configuration file is stored in ~/.nxqddb_config/RelationPathName. Given the full pathname of your database (say /u/joe/data/mine), nxqddb(1) will store the configuration in ~/.nxqddb_config/ If you have multiple people accessing
your database, you can provide a default configuration by saving the Global configuration. From that point on, anyone accessing your data will get the defaults. Any custom configuration they might do to their Personal configuration overrides the defaults.


Expandable attributes have three buttons: Add, View, and Del. The Add button inserts a new blank instance for the attribute next to the button. The View button brings up a configurable listbox of the current set of values for the expandable attribute. The skull/crossbones button deletes the currently viewed instance. When an instance is deleted, the current view is adjusted so that another value is shown. If another instance doesn't exist, then a blank instance is shown. If you happen to delete some instances and want to undo the deletions, you can click on the Undo button. The Undo button undoes all changes since you brought the tuple into view. Undo will also try to obtain a lock on the tuple if you don't already have it and you do not have the Force Read-only Mode configuration option turned on. If the lock is obtained, you will be placed into Change Mode.


Both the search results and all instance views may be printed by clicking on the Print button at the bottom of the listboxes. A printing dialog will appear, and you can type the name of a printer, a file name, or file name for a DOS floppy (assuming you have mtools).


Dates are formatted with the format specified in the Schema. The exception to this rule is when a format is ambiguous, such as "%m/%d/%y". For this reason, you can configure nxqddb to use either "%m/%d/%y" or "%d/%m/%y" with the QDDB_DATESTYLE environment variable:

# %m/%d/%y style
# %d/%m/%y style

You can also configure nxqddb's date style through the Configure menu.


nxqddb should work properly on monochrome displays if you have your .Xdefaults set up for use with other Tk-based programs. If you tend to use a dark background and light foreground, you may want to add something like the following lines to your .Xdefaults file.

#ifndef COLOR
*Entry*foreground: black
*Entry*background: white
*Text*foreground: black
*Text*background: white
*Listbox*foreground: black
*Listbox*background: white
*Button*foreground: black
*Button*background: white
*Scrollbar*foreground: white
*Scrollbar*background: black
*Label*foreground: white
*Label*background: black
*activeForeground: black
*activeBackground: white
*Checkbutton*selector: white
*Radiobutton*selector: white
*Menu*selector: white


For those of you that do not typically use Tk-based applications, the <Alt> key should be mapped as <Mod2>. Anywhere you see <Alt> as an accelerator, use whatever you have bound as <Mod2>. On a PC keyboard, you can: xmodmap -e "clear Mod1"
xmodmap -e "clear Mod2"
xmodmap -e "add Mod2 = Alt_L"


qedit(1), query(1), qnewdb(1), qstall(1), A Guide to Qddb


nxqddb(1) was designed as an example for writing custom database applications. It was not intended for production use, but it is quite suitable for small applications. If you need a specialized application, we recommend that you study the nxqddb(1) code, read the section "n" manual pages (especially Fx(n)), and/or write your own TCL code for qddb_wish. A Guide to Qddb has chapters on writing your own Qtcl scripts.

Some systems require #! scripts to have interpreters with paths less than 32 characters. For this reason, qddb_wish is named qwish and qddb_tclsh is named qtclsh. Links are made to qddb_wish and qddb_tclsh respectively. Other systems will not let you use #! scripts with an interpreter that is not in /etc/shells. You can always start up nxqddb(1) by:
$ qddb_wish /usr/local/qddb/bin/nxqddb Relation


Key and mouse bindings should probably be configurable.


A Guide to QDDB
Eric H. Herrin II and Raphael A. Finkel

Qddb User's Guide

An ASCII Database for Fast Queries of Relatively Stable Data Eric H. Herrin II and Raphael A. Finkel Computing Systems, Volume 4 Number 2
University of California Press, Berkeley CA

Schema and Tuple Trees: An Intuitive Structure for Representing Relational Data
Eric H. Herrin, II and Raphael A. Finkel Computing Systems, Volume 9, Number 2
MIT Press, Cambridge MA

Table of Contents