CMSC 661: RDB Users Manual

CMSC 661: Principles of Database Systems

[UMBC | CSEE | CS | Courses | Grad | 661 | Fall 95 ]

RDB - A Relational Database Management System

User Manual

Copyright (c) Rishiyur Nikhil, 20-Jan-1982
Department of Computer and Information Sciences
University of Pennsylvania

Philadelphia, PA 19104

Introduction

This is a brief manual describing the use of the RDB system. It assumes that you have already been introduced to the relational data model and relational algebra (see references).

In what follows, the following BNF notation is used:

To run RDB, you say, at monitor level (this may change slightly on different machines):
    rdb
RDB responds with the top-level prompt
    RDB>
At the top level, you can type in i.e.,
    TopLevelInput       ::=   "help" ";"
                              expr ";"
                              binding ";"
                              command ";"
Tokens may be separated by arbitrary spaces, newlines and comments. Comments are arbitrary text enclosed by "/*" and "*/" brackets. If you type in a newline within an expression, definition or command, RDB's prompt changes to

    ...>

It is restored to RDB> when you return to the top level. Remember, toplevel inputs ALWAYS end with a semicolon.

The three types of toplevel inputs will now be separately described.

Evaluating an Expression

The concrete syntax of expressions is given below.

    expr                ::=   "if" expr "then" expr "else" expr
                              "lambda" "(" [idList] ")" "." expr
                              simpleExpr [comparisonOp simpleExpr]

    comparisonOp        ::=   "<" | "<=" | "=" | "<>" | ">=" | ">"

    simpleExpr          ::=   [prefixOp] term {addOp term}

    prefixOp            ::=   "+" | "-" | "not"
    addOp               ::=   "+" | "-" | "or"

    term                ::=   factor {multOp factor}

    multOp              ::=   "*" | "/" | "div" | "mod" | "and"

    factor              ::=   boolConst | unsignedInt
                              charString   | literalRelation
                              id [ "(" [argList] ")" ]
                              "(" expr ")"
                              "reduce" "(" expr "," expr "," expr ")"
                              "project" expr "over" attribList
                              "restrict" expr "with" expr
                              "join" expr "with" expr ["on" attribList]
                              "rename" attribList "to" idList "in" expr
                              "insert" expr

    argList             ::=   expr {"," expr}

    literalRelation     ::=   "{" idList [tupleList] "}"
    tupleList           ::=   tuple {tuple}
    tuple               ::=   "[" atomicValue {atomicValue} "]"
    atomicValue         ::=   integer | charString
                              boolConst | id

    idList              ::=   id {"," id}

    attribList          ::=   attrib {"," attrib}
    attrib              ::=   id [":" unsignedInt]

    id                  ::=   letter {restChars}
    restChars           ::=   letter | digit | "_"

    integer             ::=   ["-"] unsignedInt
    unsignedInt         ::=   digit {digit}

    charString          ::=   "'" anyNonControlChars "'"

    boolConst ::= "true" | "false"

Notes:

Semantics of Expressions

comparisonOps work on two values of any type other than function values. The ordering on integers is the usual ordering; on booleans it is "false < true"; on charStrings it is lexicographic; and on relations it is that of set inclusion. To be comparable, two relations must have the same attribute names and associated datatypes (in the same order).

The infix operators "+", "-" and "*" work on integers as usual, and on relations as the set union, difference and intersection operations. The "+" operation also concatenates charStrings.

The infix operator "/" is the "divide" operator on relations; it does NOT work on any other type. Division on integers is done using the infix "div" operator.

An identifier followed by 0 or more expressions in parentheses corresponds to function application.

Literal relations are written enclosed by braces. After the "{", the idList names the columns in the relation. After that comes zero or more tuples, followed by "}". Each tuple (row) has one or more data values enclosed in square brackets, which may be integers, booleans or charStrings.

"project" projects the relation (expr) over the attributes named in the attribList.

"restrict" restricts the relation (first expr) to those tuples that satisfy the predicate (second expr).

"join" joins the first relation (first expr) with the second relation (second expr) on the attributes named by the attribList. The join is an equi-join. If the ""on" attribList" clause is omitted, it performs the general cross-product of the two relations.

"rename" renames the columns named by attribList to the names in idList in the relation expr.

"insert" allows one to interactively type in tuples of relations. The expr is first evaluated to get a (possibly empty) relation. RDB then uses the attribute names of this relation to prompt you for further tuples. As soon as at least one tuple is known, RDB begins to enforce subsequent tuples to have the same datatypes.

Attribute names (attribs) are just identifiers, at their simplest. However, relations may have more than one column with the same name. Thus attribute names may be qualified by a ":n", where n is an unsigned integer. Thus, for example, "CITY:3" stands for the third column named "CITY".

"reduce" may be used to find the cardinality of a relation, totals over columns, max and min values in a column, etc. The first expr should evaluate to a relation, the second should be a unary function, and the third may be any value. "reduce" will iterate over all the tuples in the relation, repeatedly applying the function to an accumulator value to produce a new accumulator value. The initial accumulator value is the value of the third expr; the final value is returned.

Creating bindings

At the top level, identifiers may be bound to values. The syntax is
    binding             ::=   "let" id [argstruc] "=" expr

    argstruc            ::=   "(" [idList] ")"

This causes a value to be bound to the identifier (id). If no argstruc is given, the expr is evaluated and its value bound to the identifier. If an argstruc is given, then a function value is bound to the identifier; the argstruc represents its formal parameters and expr represents its body.

Identifiers may be used in expressions, where they represent the values that they are bound to. There is a special identifier "it", which always represents the most recent value resulting from toplevel expression evaluation.

Commands

At the top level, you can execute a command. The syntax is

    command             ::=   "use" filename
                              "save" [idList] "in" filename
                              "bindings"
                              "exit"

    filename            ::=   charString

The "use" command treats the text in the named file as if it were typed in at the terminal. This is the most convenient way of entering large relations -- create a file with a text editor, and load it into RDB with "use".

The "save" command saves the identifier bindings named in idList in the named file, as text. The bindings can be reloaded from the file with the "use" command, or edited with a text editor. If idList is omitted, all current bindings are saved.

In both "use" and "save", the default file extension is ".rdb".

The "bindings" command shows all identifiers currently bound, along with their datatypes (integer, boolean, charString, relation or function).

The "exit" command takes you out of RDB back to the monitor.

Examples

Naturally, all this is gobbledegook till we see some examples:

    RDB> 23;
    23

    RDB> 23+2*5;
    33

    RDB> (23+2)*5;
    125

    RDB> 5 + it;
    130

    RDB> let x = 20*4;
    value x

    RDB  x - it;
    -50

    RDB> let f(y) = y div 2;
    function f

    RDB> f(x);
    40

    RDB> let s = {snum sname status city
    ...>         [s1   Jones  20    London]
    ...>         [s2   Blake  30    Paris ]
    ...>         [s3   Brown  50    Paris ]};
    value s

    RDB> s;
    --------------------------
    |snum|sname|status|city  |
    --------------------------
    |s3  |Brown|    50|Paris |
    |s2  |Blake|    30|Paris |
    |s1  |Jones|    20|London|
    --------------------------

    RDB> let sp = {snum part weight [s2 Nut 10]
    ...>           [s2 Bolt 20][s1 Washer 25]};
    value sp

    RDB> join s with sp on snum;
    ----------------------------------------
    |snum|sname|status|city  |part  |weight|
    ----------------------------------------
    |s2  |Blake|    30|Paris |Nut   |    10|
    |s2  |Blake|    30|Paris |Bolt  |    20|
    |s1  |Jones|    20|London|Washer|    25|
    ----------------------------------------

    RDB> restrict it with (weight >= 20) and (city='Paris');
    ----------------------------------------
    |snum|sname|status|city  |part  |weight|
    ----------------------------------------
    |s2  |Blake|    30|Paris |Bolt  |    20|
    ----------------------------------------

    RDB> project s over city;
    --------
    |city  |
    --------
    |Paris |
    |London|
    --------

    RDB> bindings;
    x : integer
    f : function
    s : relation
    sp : relation

    RDB> save f,s in 'temp.rdb';
    f saved
    s saved

    RDB> save in 'all';
    x saved
    f saved
    s saved
    sp saved

    RDB> let f(x) = weight + x;
    function f

    RDB> let add1(x) = 1+x;
    function add1

    RDB> /* total weight is */        reduce(sp,f,0);
    55

    RDB> /* cardinality of sp is */   reduce(sp,add1,0);
    3

    RDB> /* average weight */         reduce(sp,f,0) div it;
    18

    RDB> exit;


References

Date,C.J., An Introduction to Database Systems, Addison Wesley.