Session Examples

## 4 Session Examples

### 4.1 Example Introduction

In this and the following chapter several examples of the usage of the Mnesia_Session interface will be introduced. The examples will first be written in Erlang and than the same functionality will be shown in a foreign language.

The examples will contain some basic operations, create_table, write and read records both via the `mnesia_session` and the `mnesia_corba_session` interfaces.

#### 4.1.1 Data Definition

A simple database has been created, with people as the subject. The person record containing other data types will be demonstrated in the rest of the examples. To begin with we define the data types that will be used in IDL.

    //
    // A simple example on different structures used to access mnesia from
    // the outside
    //
    // If the tables and structures should be accessed through a corba
    // interface, they need to be defined in a IDL specification so that
    // the mnesia_session interface can access the types needed to use
    // corba type any.
    //

    module persons
    {
      enum Sex {male, female};

      struct data
      {
        Sex sex;
        long age;
        long phone;
      };

      struct person
      {
        string name;                 // Used as key
        data personData;             // A reference to other data structure
        string married_to;           // A relation
        sequence <string> children;  // A list
      };

    };

Observe that the struct person, when mapping from IDL to Erlang, is prefixed with the module name followed by '_'. In this example, the table name would be `persons_person`. If this is not wanted the struct definition should be placed on the top level, i.e. above the module definition.

### 4.2 A Session Example in Erlang

A simplified example of a client written in Erlang to access `Mnesia` via the session interface is shown below.

Compile the person data definitions with:

    erlc +'{be, erl_genserv}' person.idl

Include the necessary files:

    %% Include to get the mnesia types, used in create table
    -include_lib("mnesia_session/include/mnesia.hrl").

    %% Include my own definitions
    -include("persons.hrl").

Find the connector and create a private session:

    start_session(Node) ->
        ConnPid = rpc:call(Node, mnesia_session_lib, lookup_connector, []),
        %% Use the factory to create a session
        SessPid = mnesia_connector:connect(ConnPid),
        {ConnPid, SessPid}.

In this example, we used `mnesia_session_lib:lookup_connector/0` but it is also possible to use `erlang:whereis(mnesia_connector)`. In Erlang, objects are represented as processes. To access the method of the object, call the method where the first argument is the object reference, as in `mnesia_connector:connect(ConnPid)`.

All functions in the IDL specification have an additional first argument which is the object reference. More information is given in the `IC` and `Orber` documentation.

To create a table with the structure defined in the IDL definition, we use the function create_person_table.

Define the table properties and call the function:

    create_person_table(ObjKey) ->
        %% Define the table properties
        Attrs = [atom_to_list(F) || F <- record_info(fields, persons_person)],
        TabDef = #mnesia_TableDef{type = bag, mode = read_write,
                                  ram_copies = [],
                                  disc_copies = [],
                                  disc_only_copies = [],
                                  index_list = [4],  %% Index on married_to
                                  attributes = Attrs,
                                  %% OBSERVE that the record_name must be
                                  %% exactly the same as the name of the
                                  %% structure/record
                                  record_name = "persons_person"},

        Res = mnesia_session:create_table(ObjKey, "persons", TabDef),
        case Res of
            {ok, ""} ->
                ok;
            Else->
                io:format("ERROR: ~s~n", [Else])
        end.

The example insert and a read operation looks like:

    insert_person(SessionKey, Name, Sex, Age, Phone, Mt, Ch)
      when list(Name), atom(Sex), integer(Age),
           integer(Phone), list(Mt), list(Ch) ->

        Data = #persons_data{sex = Sex, age = Age, phone = Phone},
        Person = #persons_person{name = Name, personData = Data,
                                 married_to = Mt, children = Ch},

        {ok, ""} = mnesia_session:dirty_write(SessionKey, "persons", Person),
        Person.

    get_person(SessionKey, Name) when list(Name) ->
        {ok, RObj, ""} =
            mnesia_session:dirty_read(SessionKey, "persons", Name),
        hd(RObj).

### 4.3 A Session Example in Java

Compile the person data definitions:

    erlc +'{be, java}' person.idl

Import the necessary files.

    import com.ericsson.otp.ic.*;

Find the connector and create a private session:

      public static mnesia._sessionStub start_session(String args[])
        {
          String SNode = new String(args[0]);
          String PNode = new String(args[1]);
          String Cookie = new String(args[2]);

          mnesia._connectorStub mccRef = null;
          mnesia._sessionStub mcsRef = null;

          try
            {

              mccRef = new mnesia._connectorStub(SNode+"0",PNode,Cookie,
                                                 "mnesia_connector");

              com.ericsson.otp.ic.Pid mccPid = mccRef.connect();

              mcsRef = new mnesia._sessionStub(SNode+"1",PNode,Cookie,mccPid);

              return mcsRef;
            }
          catch(Exception se)
            {
              System.out.println("Unexpected exception: " + se.toString());
              se.printStackTrace();
              return null;
            }
        }

To create a table with the structure defined in the IDL definition, we use the function create_person_table. Define the table properties and call the function.

      public static void create_person_table(mnesia._sessionStub mcsRef)
        {
          try {

            String name = "persons";
            mnesia.TableDef def = new mnesia.TableDef();
            def.type = mnesia.SetOrBag.bag;
            def.mode = mnesia.AccessMode.read_write;
            def.ram_copies = new String[0];
            def.disc_copies = new String[0];
            def.disc_only_copies = new String[0];
            int[] idxs = new int[1];
            idxs[0] = 4;
            def.index_list = idxs;
            String[] attrs = new String[4];
            attrs[0] = "name";
            attrs[1] = "personData";
            attrs[2] = "married_to";
            attrs[3] = "children";
            def.attributes = attrs;
            def.record_name = "persons_person"; // The used IDL type

            StringHolder reason;
            reason = new StringHolder();

            if(mnesia.Status.ok != mcsRef.create_table(name, def, reason))
              System.out.println("Create Table Error " + reason.value);
          }
          catch(Exception se)
            {
              System.out.println("Unexpected exception: " + se.toString());
              return;
            }
        }

The example insert and a read operation looks like:

      public static void insert_person(mnesia._sessionStub mcsRef,
                                       String name,
                                       persons.Sex sex,
                                       int age,
                                       int phone,
                                       String mt,
                                       java.lang.String[] children)
        {
          persons.data data;
          data = new persons.data(sex, age, phone);
          persons.person person = new persons.person();
          person.name = name;
          person.personData = data;
          person.married_to = mt;
          person.children = children;

          try
            {
              StringHolder reason = new StringHolder();
              Term object = new Term();
              persons.personHelper.insert(object,person);

              if(mnesia.Status.ok != mcsRef.dirty_write("persons", object, reason))
                System.out.println("Insert person Error " + reason.value);
            }
          catch(Exception se)
            {
              System.out.println("Unexpected exception: " + se.toString());
              return;
            }
        }

      public static persons.person
        get_person(mnesia._sessionStub mcsRef, String name)
        {
          try
            {
              StringHolder reason = new StringHolder();
              Term key = new Term();
              mnesia.RecordlistHolder res = new mnesia.RecordlistHolder();
              key.insert_string(name);

              if(mnesia.Status.ok == mcsRef.dirty_read("persons",
                                                       key, res, reason))
                {
                  if(res.value.length > 0)
                    {
                      persons.person rec1 =
                        persons.personHelper.extract(res.value[0]);

                      return rec1;
                    }
                  else
                    return null;
                }
              else
                {
                  System.out.println("Insert person Error " + reason.value);
                  return null;
                }
            }
            catch(Exception se)
              {
                System.out.println("Unexpected exception: " + se.toString());
                return null;
              }
        }

Note: the usage of `ETERM` differs a little to the CORBA case, when using Java it mapps to the `Term` class which inherits from `Any` class.

### 4.4 A Session Example in C

Compile the person data definitions:

    erlc +'{be, c_genserv}' person.idl

Include the necessary files.

    #include <erl_interface.h>
    #include "mnesia_session.h"
    #include "mnesia_connector.h"
    #include "persons.h"
    #include <ic.h>

Find the connector and create a private session:

    erlang_pid start_session(CORBA_Environment * env)
    {
        erlang_pid session_pid;

        session_pid = mnesia_connector_connect(NULL, env);

        if(env->_major != CORBA_NO_EXCEPTION)
            handle_error("connector_connect", env);
        return session_pid;
    }

To create a table with the structure defined in the IDL definition, we use the function create_person_table. Define the table properties and call the function.

    void create_person_table(CORBA_Environment * env)
    {
        int err;
        char * reason;
        mnesia_Status result;
        mnesia_TableDef tabdef;
        mnesia_Indices idxs;

        long idx_list[1] = {4};
        char * attrs[4] = {"name", "personData", "married_to", "children"};

        tabdef.type = mnesia_bag;
        tabdef.mode = mnesia_read_write;

        tabdef.ram_copies._maximum = 0;
        tabdef.ram_copies._length = 0;
        tabdef.ram_copies._buffer = NULL;

        tabdef.disc_copies._maximum = 0;
        tabdef.disc_copies._length = 0;
        tabdef.disc_copies._buffer = NULL;

        tabdef.disc_only_copies._maximum = 0;
        tabdef.disc_only_copies._length = 0;
        tabdef.disc_only_copies._buffer = NULL;

        tabdef.index_list._maximum = 5;
        tabdef.index_list._length = 1;
        tabdef.index_list._buffer = idx_list;

        tabdef.attributes._maximum = 5;
        tabdef.attributes._length = 4;
        tabdef.attributes._buffer = attrs;

        tabdef.record_name = "persons_person"; /* The name of the stored
                                                  type/struct */

        result = mnesia_session_create_table(NULL, "persons", &tabdef, &reason, env);

        if(env->_major != CORBA_NO_EXCEPTION)
        {
            fprintf(stderr,"\n error in create_table: %d\n", env->_major);
            exit(1);
        }
        else if(result != mnesia_ok)
        {
            fprintf(stderr, "Create table failed with reason %s", reason);
        }
        CORBA_free(reason);
    }

The example insert and a read operation looks like:

    void insert_person(CORBA_Environment * env,
                       char *name, persons_Sex sex, int age,
                       int phone, char * mt, persons_person_children * ch)
    {
        ETERM *person, *children, *temp;
        int err, i;
        char * reason;
        mnesia_Status result;
        extern char * oe_persons_Sex[];

        children = erl_mk_empty_list();

        if(ch != NULL)
            for(i = 0; i < ch->_length; i++)
            {
                temp = erl_mk_string(ch->_buffer[i]);
                children = erl_cons(temp, children);
                erl_free_term(temp);
            };

        person = erl_format("{persons_person,~s,{persons_data,~a,~i,~i}, ~s, ~w}",
                            name, oe_persons_Sex[sex], age, phone, mt, children);

        result = mnesia_session_dirty_write(NULL, "persons", person, &reason, env);

        if(env->_major != CORBA_NO_EXCEPTION)
        {
            fprintf(stderr,"\n error in insert_person: %d\n", env->_major);
            exit(1);
        }
        else if(result != mnesia_ok)
        {
            fprintf(stderr, "Insert person failed with reason %s", reason);
            exit(-1);
        }

        erl_free_term(children);
        erl_free_term(person);

        CORBA_free(reason);
    }

    void get_person(CORBA_Environment * env, char * name, persons_person * person)
    {
        int err, i;
        char * reason;
        mnesia_Status result;
        mnesia_Recordlist *rec_list;
        ETERM * key;

        key = erl_mk_string(name);

        result = mnesia_session_dirty_read(NULL, "persons", key, &rec_list,
                                           &reason, env);
        if(env->_major != CORBA_NO_EXCEPTION)
        {
            fprintf(stderr,"\n error in get_person: %d\n", env->_major);
            exit(1);
        }
        else if(result != mnesia_ok)
        {
            fprintf(stderr, "Get person failed with reason %s", reason);
            exit(-1);
        }

        if(rec_list->_length > 0)
        {
            /* Only interrested in the first match */
            decode_person(rec_list->_buffer[0], person);
            for(i=0; i < rec_list->_length; i++)
                erl_free_term(rec_list->_buffer[i]);
        }
        else
        {
            fprintf(stderr, "Insert person failed empty_list returned ");
            exit(-1);
        }

        CORBA_free(rec_list);
        CORBA_free(reason);
        erl_free_term(key);
    }

Note: the usage of `ETERM` differs when using C as the user must develop their own code to create and extract information from the `ETERM` structures, whereas, CORBA does this automatically.

Copyright © 1991-2007 Ericsson AB