BRL is not a full featured DBMS. It does not support all ideas of the Binary Relations Approach. BRL is however a small, fast and reliable engine. BRL provides basic tools for using binary relations in C programs.There are some limitations of BRL v1.1 release:
1. At the same time You can open up to 40 binary relations.
2. You can use only Oid4 and String types as key types of binary relations.
3. The sum of key and value sizes must be less than 336 bytes.
There are very few basic concepts that you need to know. We describe the concepts as abstract data types. There is a 1:1 correspondence between BRL abstract data types and the Binary Relations Approach basic items.
BinaryRelations Approach BRLobject The ADT BINARY OBJECT implements an abstract "binary object in memory" type. binary relation The ADT BINARY RELATION provides a simple mechanism for associating two BINARY OBJECT types, known as the value and the key, in one BINARY RELATION type. database The ADT DATABASE is a collection of binary relations. It also provides the file and memory management capabilities
An example information structure is a part of more complex structure in Picture 2 in BinaryRelations Approach. This is done for clarity and conciseness. All the code examples are incomplete. They are however, extracted from real examples supplied with BRL.
Creating a Database
This code creates an example database and "zeroes" it. This database can have up to 32 binary relations.
/* exmpl01.c: Creating a Database */ #include "stdio.h" #include "brl.h" int main() { if(! brDBCreate("example", 32) ) { printf("Can not create example database\n"); return(1); } printf("The database is created\n"); brDBClose(); return(0); }Accessing a Database
Once you have constructed a database, you can access it.
/* exmpl02.c Accessing a Database */ #include "stdio.h" #include "brl.h" int main() { if(! brDBOpen("example") ) { printf("Can not open example database"); return(1); } printf("The database is open\n"); brDBClose(); return(0); }Destroying a Database
You should close the database before destroy it.
#include "brl.h" DBClose();Then you can destroy it using a system command. For example, for UNIX we will write:
rm example
Creating a New Relation
You can create a new relation by specifying the relation name, key and value object sizes and the cardinal.
/* * exmpl03.c Create, Access and Destroy Relations. */ #include "stdio.h" #include "brl.h" #define EMP_SZ 4 #define EMPNAME_SZ 40 int main() { int result; BR *employee_name; if(! brDBOpen("example") ) { printf("Can not open example database"); return(1); } /*------------------------------------------------------ * Creating a New Relation. *-----------------------------------------------------*/ employee_name = brDBAdd("employee_name", EMP_SZ,EMPNAME_SZ, UNIQUE ); if(employee_name) printf("A new relation is created\n");\ else { printf("Can not create the relation\n"); return(1); } brClose(employee_name);Accessing a Relation
Once you have constructed a relation, you can access it. This code opens the relation.
/*---------------------------------------------------------- * Accessing a Relation. *----------------------------------------------------------*/ employee_name = brOpen("employee_name" ); if(employee_name) printf("The relation is open\n");\ else { printf("Can not open the relation\n"); return(1); }Destroying a Relation
You should close the relation before destroy it./*------------------------------------------------------ * Destroying a Relation. *------------------------------------------------------*/ brClose(employee_name); result= brDBDestroy("employee_name"); if(result) printf("The relation is destroyed\n");\ else { printf("Can not destroy the relation\n"); return(1); } brDBClose(); return(0); }Populating a Relation with Pairs
/* exmpl04.c Populating a Relation with Pairs */ #include "stdio.h" #include "brl.h" #define EMP_SZ 4 #define EMPNAME_SZ 40 int main() { BR *employee_name; BOB *emp, *empname; if(! brDBOpen("example") ) { printf("Can not open example database"); return(1); } employee_name = brDBAdd("employee_name", EMP_SZ,EMPNAME_SZ, UNIQUE ); if(employee_name) printf("A new relation is created\n");\ else { printf("Can not create the relation\n"); return(1); } brClose(employee_name); /* Open the relation and populate it */ employee_name = brOpen("employee_name"); emp = brKeyObj(employee_name); empname = brValueObj(employee_name); brObjWriteOid4(emp,1); brObjWriteString(empname, "Shelby T. Chapman"); brAdd(employee_name,emp,empname); brObjWriteOid4(emp,2); brObjWriteString(empname, "Helen Smith"); brAdd(employee_name,emp,empname); brObjWriteOid4(emp,3); brObjWriteString(empname, "Mark Davidson"); brAdd(employee_name,emp,empname); brObjWriteOid4(emp,4); brObjWriteString(empname, "David Wilson"); brAdd(employee_name,emp,empname); brObjWriteOid4(emp,5); brObjWriteString(empname, "Rick D. Bruther"); brAdd(employee_name,emp,empname); brObjWriteOid4(emp,6); brObjWriteString(empname, "Joe Smith"); brAdd(employee_name,emp,empname); brObjWriteOid4(emp,7); brObjWriteString(empname, "Joe Curry"); brAdd(employee_name,emp,empname); brObjWriteOid4(emp,8); brObjWriteString(empname, "Elizabeth Culver"); brAdd(employee_name,emp,empname); brObjWriteOid4(emp,9); brObjWriteString(empname, "Suzanne B. Symmes"); brAdd(employee_name,emp,empname); brObjWriteOid4(emp,10); brObjWriteString(empname, "Eric D'Enfant"); brAdd(employee_name,emp,empname); brClose(employee_name); brDBClose(); return(0); }Updates
You can update the current pair of the relation.
#include "brl.h" BR *employee_name; BOB *name; if(! brDBOpen("example")) ) { printf("Can not open example database"); return(1); } employee_name = brOpen("employee_name" ); ... name= brValueObj(employee_name); brObjWriteString(name, "Joe Coock"); brUpdate(employee_name,name);Deletions
You can delete the current pair of the relation.#include "brl.h" BR *employee_name; if(! brDBOpen("example")) ) { printf("Can not open example database"); return(1); } employee_name = brOpen("employee_name"); ... brDestroy(employee_name ); /* Deletes the current pair */Scanning a Relation
You can use traversing or scanning a relation, accessing each stored pair of objects in turn to perform some test or action.
/* exmpl05.c Scanning a Relation */ #include "stdio.h" #include "brl.h" int main() { char *tmp; int more; BR *employee_name; BR_TEMPL *templ; if(! brDBOpen("example") ) { printf("Can not open example database"); return(1); } employee_name = brOpen("employee_name" ); /*-------------------------------------------------------------- * You can use traversing or scanning a relation, accessing each * stored pair of objects in turn to perform some test or action. *-------------------------------------------------------------*/ printf("\nScan from the first pair.\n"); more= brFirst(employee_name); while(more) { /* some test or action */ printf("%ld %s\n", brObjReadOid4(brKey(employee_name)), brObjReadString(brValue(employee_name))); more= brNext(employee_name); } printf("\nScan from the last pair.\n"); more= brLast(employee_name); while(more) { /* some test or action */ printf("%ld %s\n", brObjReadOid4(brKey(employee_name)), brObjReadString(brValue(employee_name))); more= brPrev(employee_name); } brClose(employee_name); brDBClose(); return(0); }Evaluating a Relation
We can "navigate" from objects to objects using binary relations. To do this in C, we use brEval, bEvalFirst, brEvalLast functions. These functions enables us to access abstract objects, as well as to follow relations. For instance, we have a Employee "emp" and want to know a name of the manager of the employee. The code is:
/* exmpl07.c Evaluating Relations */ #include "stdio.h" #include "brl.h" int main() { BR *employee_name, *manager_employee, *employee_manager; int more; BOB *emp, *mgr, *empname; BOB *emp_mgr_name; if(! brDBOpen("example") ) { printf("Can not open example database"); return(1); } employee_name = brOpen("employee_name" ); employee_manager =brOpen("employee_manager"); manager_employee= brOpen("manager_employee"); emp= brObjCopy(brKeyObj(employee_name)); brObjWriteOid4(emp,8); emp_mgr_name = brEval(employee_name, brEval(employee_manager, emp)); printf("The name of the manager of the employee 8:\n%s\n", brObjReadString(emp_mgr_name)); /*---------------------------------------------------------- * Let us now look at multiple relations. Assume we want the * names of the employees of the manager "mgr". * We write: *---------------------------------------------------------*/ mgr= brObjCopy(emp); brObjWriteOid4(mgr,9); printf("\n\nNames of the employees of the manager 9:\n"); if(brEvalFirst(manager_employee, mgr)!= 0) more =1; else more =0; while(more && (brObjReadOid4(brKey(manager_employee)) == brObjReadOid4(mgr))) { empname= brEval(employee_name, brValue(manager_employee)); printf("%s\n", brObjReadString(empname)); more= brNext(manager_employee); } brClose(employee_name); brClose(employee_manager); brClose(manager_employee); brDBClose(); return(0); }So we have means to navigate from an object towards any object following any relation.
BRL regards an object type as a "binary object of memory". That is, BRL will only store and retrieve the data from disk and use your user-defined functions to input and output the data.
Objects types are divided into base types and abstract types. Base types are those, like int, char, float, etc that are implemented in a language such as C. Abstract types generally correspond to abstract data types . One can only operate on such types through binary relations. Abstract types are created whenever the user creates binary relations. After the defining abstract object types you can generate new types and build different hierarchies of types. We demonstrate it for our example database.
/* exmpl06.c Hierarchies of types */ #include "stdio.h" #include "brl.h" #define EMP_SZ 4 #define EMPNAME_SZ 40 #define PROJ_SZ 4 #define PRJNAME_SZ 40 int main() { BR *employee_name, *manager_employee, *employee_manager, *project_name, *name_project, *employee_project, *project_employee, *manager_project, *project_manager; if(! brDBCreate("example",32) ) { printf("Can not create example database"); return(1); } /* Inform the database that "Employees have names". For it * we add an EMPLOYEE abstract type */ employee_name = brDBAdd("employee_name", EMP_SZ, EMPNAME_SZ, UNIQUE ); brClose(employee_name); /*------------------------------------------------------- * Inform the database that "Some of employees are managers * and have subordinates." For it we add a new abstract type * MANAGER OF EMPLOYEES as a subtype of EMPLOYEE. *------------------------------------------------------*/ manager_employee = brDBAdd("manager_employee", EMP_SZ, EMP_SZ, MULTIPLE); brClose(manager_employee); employee_manager = brDBAdd("employee_manager", EMP_SZ, EMP_SZ, UNIQUE ); brClose(employee_manager); /*------------------------------------------------------- * Inform the database that "Projects have names". For it we * add a new abstract type PROJ. *-------------------------------------------------------*/ project_name= brDBAdd("project_name", PROJ_SZ, PRJNAME_SZ, UNIQUE); brClose(project_name); name_project= brDBAdd("name_project", PRJNAME_SZ, PROJ_SZ, UNIQUE ); brClose(name_project); /*------------------------------------------------------- * Inform the database that "Some of employees take part in * projects." For it we add a new abstract type MEMBER OF * PROJECT as a subtype of EMPLOYEE. *-------------------------------------------------------*/ employee_project= brDBAdd("employee_project", EMP_SZ, PROJ_SZ, MULTIPLE); brClose(employee_project); project_employee= brDBAdd("project_employee", PROJ_SZ, EMP_SZ, MULTIPLE); brClose(project_employee); /*------------------------------------------------------- * Inform the database that "Some of employees that take part * in projects are managers of projects." For it we add a new * abstract type MANAGER OF PROJECT as a subtype of * MEMBER OF PROJECT. *-------------------------------------------------------*/ manager_project = brDBAdd("manager_project", EMP_SZ, PROJ_SZ, MULTIPLE); brClose(manager_project); project_manager = brDBAdd("project_manager", PROJ_SZ, EMP_SZ, UNIQUE ); brClose(project_manager); brDBClose(); return(0); }
We have already seen that BinaryRelations have a powerful, flexible and simple data model. Here, we demonstrate how to use BinaryRelations to represent C structures.For example, we will define a circle type. Circles have a centre and a radius. So reasonable declarations are:
/* exmpl08.c C Structures */ #include "stdio.h" #include "brl.h" #define ID_SZ 4 #define COORD_SZ 8 #define RADIUS_SZ 8 typedef struct { double x,y; } POINT; typedef struct { POINT center; double r; } CIRCLE; void CirclePrint(CIRCLE* pcircle) { printf("center x coord: %lf\n",pcircle->center.x); printf("center y coord: %lf\n",pcircle->center.y); printf("radius: %lf\n",pcircle->r); } CIRCLE item = { { 24.15, 100.19 }, 12.24 }; CIRCLE nullitem = { { 0, 0 }, 0 }; int main() { BR *point_xcoord, *point_ycoord, *point_radius; BOB *id, *coord, *radius; CIRCLE *pcircle; /* Create graphic database */ if(! brDBCreate("graphic",32) ) { printf("Can not create graphic database"); return(1); } /* Add abstract type POINT */ point_xcoord = brDBAdd("point_xcoord", ID_SZ, COORD_SZ, UNIQUE ); brClose(point_xcoord); point_ycoord = brDBAdd("point_ycoord", ID_SZ, COORD_SZ, UNIQUE ); brClose(point_ycoord); /* Add abstract type CIRCLE as a subtype of POINT */ point_radius = brDBAdd("point_radius", ID_SZ, RADIUS_SZ, UNIQUE ); brClose(point_radius); brDBClose(); /* Open graphic database */ if(! brDBOpen("graphic") ) { printf("Can not open graphic database"); return(1); } point_xcoord = brOpen("point_xcoord"); point_ycoord = brOpen("point_ycoord"); point_radius = brOpen("point_radius"); id = brObjAlloc(ID_SZ); coord = brObjAlloc(COORD_SZ); radius = brObjAlloc(RADIUS_SZ); /*--------------- Write C structure -----------------*/ printf("\nWrite circle\n"); pcircle = &item; brObjWriteOid4(id,1); brObjWriteDouble(coord,pcircle->center.x); brAdd(point_xcoord,id,coord); brObjWriteDouble(coord,pcircle->center.y); brAdd(point_ycoord,id,coord); brObjWriteDouble(radius,pcircle->r); brAdd(point_radius,id,radius); CirclePrint(pcircle); /*--------------- Read C strucutre ------------------*/ printf("\nRead circle\n"); pcircle = &nullitem; brObjWriteOid4(id,1); pcircle->center.x = brObjReadDouble(brEval(point_xcoord,id)); pcircle->center.y = brObjReadDouble(brEval(point_ycoord,id)); pcircle->r = brObjReadDouble(brEval(point_radius,id)); CirclePrint(pcircle); /*---------------------------------------------------*/ brObjFree(id); brObjFree(coord); brObjFree(radius); brClose(point_xcoord); brClose(point_ycoord); brClose(point_radius); brDBClose(); return(0); }