RDB - A RELATIONAL DATABASE MANAGEMENT SYSTEM USER MANUAL COPYRIGHT (c) Rishiyur Nikhil, 20-Jan-1982 Department of Computer and Information Sciences University of Pennsylvania / D2 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: - items in italics are non-terminals - items in quotes are terminals - items in square brackets are optional - items in curly braces may be repeated 0 or more times - alternatives are separated by vertical bars or given on separate lines To run RDB, you say, at monitor level (this may change slightly on different machines): .run rdb RDB responds with the top-level prompt RDB> At the top level, you can type in - an expression to be evaluated - an identifier binding - a command 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: ids (identifiers) and charStrings may be of any length. Upper and lower case are equivalent. When you type in an expression at the top level, RDB evaluates it and prints out the value. The value may be an integer, charString, boolean, relation or function. 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.