Using BinaryRelations Classes


Andrew Girow

Copyright © 1996 Andrew Girow. All Rights Reserved.

1. INTRODUCTION

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.


2. BASIC CONCEPTS

There are very few basic concepts that you need to know. There is a 1:1 correspondence between BRL classes and the Binary Relations Approach basic items.

   BinaryRelations Approach    BRL Classes

object The BObj class implements an abstract "binary object in memory" type. binary relation The BRel class provides a simple mechanism for associating two BObj objects, known as the value and the key, in one BINARY RELATION type. database The BData class is a collection of binary relations. It also provides the file and memory management capabilities


3. USING BRL

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.

3.1 DATABASE

Creating a Database
This code creates an example database and "zeroes" it. This database can have up to 32 binary relations.

/* exmpl01.cpp:  Creating a Database */

#include "iostream.h"
#include "bdatcls.h"

int main()
{
    if(! BData::Create("example", 32) )
    {
      cout << "Can not create example database\n";
      return(1);
    }
    cout << "The database is created\n";
    BData::Close();
    return(0);
}
Accessing a Database
Once you have constructed a database, you can access it.

/* exmpl02.cpp Accessing a Database */

#include "iostream.h"
#include "bdatcls.h"

int main()
{
    if(! BData::Open("example") )
    {
        cout << "Can not open example database\n";
        return(1);
    }
    cout << "The database is open\n";
    BData::Close();
    return(0);
}
Destroying a Database
You should close the database before destroy it.

#include "brlclass.h"

BData::Close();

Then you can destroy it using a system command. For example, for UNIX we will write:

rm example

3.2 BINARY RELATION

Creating a New Relation
You can create a new relation by specifying the relation name, key and value object sizes and the cardinal.


/*
 * exmpl03.cpp  Create, Access and Destroy Relations.
 */

#include "iostream.h"
#include "brlclass.h"

#define EMP_SZ     4
#define EMPNAME_SZ 40

int main()
{
    BRel employee_name;

    if(! BData::Open("example") )
    {
        cout << "Can not open example database\n";
        return(1);
    }

    /*-------------------------------------------------------------------
     * Creating a New Relation.
     * You can create a new relation by specifying the relation name,
     * key and value object sizes and the cardinal.
     *-------------------------------------------------------------------*/

    if(BData::Add("employee_name", EMP_SZ, EMPNAME_SZ, UNIQUE ))
       cout << "A new relation is created\n";
    else
    {
       cout << "Can not create the relation\n";
       return(1);
    }

Accessing a Relation
Once you have constructed a relation, you can access it. This code opens the relation.

    /*-------------------------------------------------------------------
     * Accessing a Relation.
     * Once you have constructed a relation, you can access it.
     *-------------------------------------------------------------------*/
    employee_name.Open("employee_name" );
    /* This code opens the relation. */
    if(!employee_name)
    {
       cout << "Can not open the relation\n";
       return(1);
    }
    cout << "The relation is open\n";
Destroying a Relation
You should close the relation before destroy it.
    /*-------------------------------------------------------------------
     * Destroying a Relation.
     * You should close the relation before destroy it.
     *-------------------------------------------------------------------*/

    employee_name.Close();
    if(BData::Destroy("employee_name"))
       cout << "The relation is destroyed\n";
    else
    {
       cout << "Can not destroy the relation\n";
       return(1);
    }

    BData::Close();
    return(0);
}

Populating a Relation with Pairs

/* exmpl04.cpp Populating a Relation with Pairs */

#include "iostream.h"
#include "brlclass.h"

#define EMP_SZ     4
#define EMPNAME_SZ 40

int main()
{

    BRel employee_name;
    BObj emp(EMP_SZ);
    BObj empname(EMPNAME_SZ);

    if(!BData::Open("example") )
    {
        cout << "Can not open example database\n";
        return(1);
    }
    if(BData::Add("employee_name", EMP_SZ, EMPNAME_SZ, UNIQUE ))
       cout << "A new relation is created\n";
    else
    {
       cout << "Can not create the relation\n";
       return(1);
    }

    /* Open the relation and populate it */
    employee_name.Open("employee_name");
    emp.WriteOid4(1); empname.WriteString("Shelby T. Chapman");
    employee_name.Add(emp,empname);

    emp.WriteOid4(2); empname.WriteString("Helen Smith");
    employee_name.Add(emp,empname);

    emp.WriteOid4(3); empname.WriteString("Mark Davidson");
    employee_name.Add(emp,empname);

    emp.WriteOid4(4); empname.WriteString("David Wilson");
    employee_name.Add(emp,empname);

    emp.WriteOid4(5); empname.WriteString("Rick D. Bruther");
    employee_name.Add(emp,empname);

    emp.WriteOid4(6); empname.WriteString("Joe Smith");
    employee_name.Add(emp,empname);

    emp.WriteOid4(7); empname.WriteString("Joe Curry");
    employee_name.Add(emp,empname);

    emp.WriteOid4(8); empname.WriteString("Elizabeth  Culver");
    employee_name.Add(emp,empname);

    emp.WriteOid4(9); empname.WriteString("Suzanne B. Symmes");
    employee_name.Add(emp,empname);

    emp.WriteOid4(10); empname.WriteString("Eric D'Enfant");
    employee_name.Add(emp,empname);

    employee_name.Close();
    BData::Close();
    return(0);
}

Updates
You can update the current pair of the relation.

#include "brlclass.h"
BRel employee_name;
employee_name.Open("employee_name" );
...
BObj &name = employee_name.Value();
name.WriteString("Joe Coock");
employee_name.Update(name);
Deletions
You can delete the current pair of the relation.
#include "brlclass.h"
BRel employee_name;

employee_name.Open("employee_name");
...

employee_name.Destroy();     /* 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.cpp Scanning a Relation */

#include "iostream.h"
#include "brlclass.h"

int main()
{
    int more;
    BRel employee_name;

    if(!BData::Open("example") )
    {
        cout << "Can not open example database\n";
        return(1);
    }
    employee_name.Open("employee_name");

    /*--------------------------------------------------------------
     * You can use traversing or scanning a relation, accessing each
     * stored pair of objects in turn to perform some test or action.
     *-------------------------------------------------------------*/
    cout << "\nScan from the first pair.\n";
    more= employee_name.First();
    while(more)
    {
        /* some test or action */
        cout << (employee_name.Key()).ReadOid4() << " "
             << (employee_name.Value()).ReadString() << "\n";
        more= employee_name.Next();
    }

    cout << "\nScan from the last pair.\n";
    more= employee_name.Last();
    while(more)
    {
        /* some test or action */
        cout << (employee_name.Key()).ReadOid4() << " "
             << (employee_name.Value()).ReadString() << "\n";
        more= employee_name.Prev();
    }

    employee_name.Close();
    BData::Close();
    return(0);
}

Evaluating a Relation

/* exmpl07.cpp Evaluating Relations */

#include "iostream.h"
#include "brlclass.h"

int main()
{
    BRel  employee_name, manager_employee, employee_manager;
    int more;

    if(! BData::Open("example") )
    {
        cout << "Can not open example database";
        return(1);
    }

    /*----------------------------------------------------------
     * 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:
     *----------------------------------------------------------*/

    employee_name.Open("employee_name" );
    employee_manager.Open("employee_manager");
    manager_employee.Open("manager_employee");

    BObj emp(employee_name.KeyObj());

    emp.WriteOid4(8);
    BObj &emp_mgr_name = employee_name(employee_manager(emp));
    cout << "The name of the manager of the employee 8: \n"
         <<  emp_mgr_name.ReadString() << "\n";

    /*----------------------------------------------------------
     * Let us now look at multiple relations. Assume we want the
     * names of the employees of the manager "mgr".
     * We write:
     *----------------------------------------------------------*/
    BObj mgr(emp);
    mgr.WriteOid4(9);
    cout << "\n\nNames of the employees of the manager 9:\n";

    emp= manager_employee(mgr,FIRST);
    if(!emp)
          more =0;
    else
          more =1;

    while(more &&
          (manager_employee.Key()).ReadOid4() == mgr.ReadOid4())
    {
          BObj &empname= employee_name(manager_employee());
          cout << empname.ReadString() << "\n";
          more= manager_employee.Next();
    }

    employee_name.Close();
    employee_manager.Close();
    manager_employee.Close();
    BData::Close();

    /*----------------------------------------------------------
     * So we have means to navigate from an object towards any
     * object following any relation.
     *----------------------------------------------------------*/
    return(0);
}

3.3 BINARY OBJECT

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.


4. BRL: ADVANCED FEATURES

4.1 HIERARCHIES OF TYPES

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.cpp Hierarchies of types */

/*----------------------------------------------------------------------
 * 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.
 *---------------------------------------------------------------------*/

#include "iostream.h"
#include "brlclass.h"

#define EMP_SZ     4
#define EMPNAME_SZ 40
#define PROJ_SZ    4
#define PRJNAME_SZ 40

int main()
{

    if( !BData::Create("example",32) )
    {
        cout << "Can not create example database";
        return(1);
    }

    /* Inform the database that "Employees have names". For it
     * we add an EMPLOYEE abstract type */
    BData::Add("employee_name", EMP_SZ, EMPNAME_SZ, UNIQUE );

    /*----------------------------------------------------------
     * 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.
     *----------------------------------------------------------*/
    BData::Add("manager_employee", EMP_SZ, EMP_SZ, MULTIPLE);
    BData::Add("employee_manager", EMP_SZ, EMP_SZ, UNIQUE );

    /*----------------------------------------------------------
     * Inform the database that "Projects have names". For it we
     * add a new abstract type PROJ.
     *----------------------------------------------------------*/
    BData::Add("project_name", PROJ_SZ, PRJNAME_SZ, UNIQUE);
    BData::Add("name_project", PRJNAME_SZ, PROJ_SZ, UNIQUE);

    /*----------------------------------------------------------
     * 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.
     *----------------------------------------------------------*/
    BData::Add("employee_project", EMP_SZ, PROJ_SZ, MULTIPLE);
    BData::Add("project_employee", PROJ_SZ, EMP_SZ, MULTIPLE);

    /*----------------------------------------------------------
     * 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.
     *----------------------------------------------------------*/
    BData::Add("manager_project", EMP_SZ, PROJ_SZ, MULTIPLE);
    BData::Add("project_manager", PROJ_SZ, EMP_SZ, UNIQUE );

    BData::Close();
    return(0);
}

4.2 C++ CLASSES


We have already seen that BinaryRelations have a powerful, flexible and simple data model. Here, we demonstrate how to use BinaryRelations to represent C++ classes.

For example, we will define a circle class. Circles have a centre and a radius. So reasonable declarations are:

/* exmpl08.cpp   C++ Classes */

#include "iostream.h"
#include "brlclass.h"

#define ID_SZ     4
#define COORD_SZ  8
#define RADIUS_SZ 8

class Point
{
  public:
    Point(double x, double y) { _x= x, _y= y; }
    virtual ~Point() {}
    double x() { return _x; }
    double y() { return _y; }
    virtual void print(void);

  private:
    double _x;
    double _y;
};

void Point::print(void)
{
   cout << "x coord: " << x() << "\n";
   cout << "y coord: " << y() << "\n";
}

class Circle: public Point
{
 public:
    Circle(double x, double y, double r):Point(x,y){ _r= r; }
    virtual ~Circle() {}
    double r() { return _r; }
    virtual void print(void);

  private:
    double _r;
};

void Circle::print(void)
{
   Point::print();
   cout << "radius: " << r() << "\n";
}


int main()
{
    BRel point_xcoord, point_ycoord, point_radius;
    BObj id(ID_SZ);
    BObj xcoord(COORD_SZ);
    BObj ycoord(COORD_SZ);
    BObj radius(RADIUS_SZ);

    /* Create graphic database */
    if(! BData::Create("graphic",32) )
    {
        cout << "Can not create graphic database";
        return(1);
    }
    /* Add abstract type POINT */
    BData::Add("point_xcoord", ID_SZ, COORD_SZ, UNIQUE );
    BData::Add("point_ycoord", ID_SZ, COORD_SZ, UNIQUE );
    /* Add abstract type CIRCLE as a subtype of POINT */
    BData::Add("point_radius", ID_SZ, RADIUS_SZ, UNIQUE );

    point_xcoord.Open("point_xcoord");
    point_ycoord.Open("point_ycoord");
    point_radius.Open("point_radius");

    /*--------------- Write C++ object -----------------*/
    cout << "\nWrite circle\n";

    Circle *pcircle= new Circle(24.15, 100.19, 12.24);
    id.WriteOid4(1); xcoord.WriteDouble(pcircle->x());
    point_xcoord.Add(id,xcoord);
    ycoord.WriteDouble(pcircle->y());
    point_ycoord.Add(id,ycoord);
    radius.WriteDouble(pcircle->r());
    point_radius.Add(id,radius);
    pcircle->print();
    delete pcircle;
    /*--------------- Read C++ object ------------------*/
    cout << "\nRead circle\n";

    id.WriteOid4(1);
    xcoord= point_xcoord(id);
    ycoord= point_ycoord(id);
    radius= point_radius(id);
    pcircle = new Circle(xcoord.ReadDouble(),ycoord.ReadDouble(),
                         radius.ReadDouble());
    pcircle->print();
    delete pcircle;

    /*---------------------------------------------------*/
    point_xcoord.Close();
    point_ycoord.Close();
    point_radius.Close();
    BData::Close();
    return(0);
}


Copyright © 1996 Andrew Girow. All Rights Reserved.
Last updated: November 14, 1996 1