Chapter 2. Getting Started With DAME

In this and following chapters, I will assume that you have a database setup using the schema provided under examples/ directory of the DAME source distribution. In this chapter we walk through a sample program developed using DAME.

Assumptions:: It is assumed that appropriate PATH and LD_LIBRARY_PATH variables have been setup so that DAME can be executed from the commandline. If you install DAME into the default location, there might not be any need for setting up of environment. Similarly, DAME Oracle™ interface library uses Oracle™'s OCI interface (library libclntsh.so) and you might have to setup the LD_LIBRARY_PATH to point to Oracle™'s lib directory.

A Simple Dame Program

Look at the following program listing (simple.dame).

simple.dame

            class CountDB
            {
                int         Count ;

                /*
                 * Select the total number employees in the employee table
                 */

                Count GetEmployeeCount (void) {
                    select count(*)
                    from emp
                } ;

            } ;
        

This program is defining a class called CountDB. The CountDB class has only one interface, GetEmployeeCount that takes no parameters and returns the variable Count.

Warning

The function GetEmployeeCount(void) defines a function that does not need any parameters. In DAME the semantics of GetEmployeeCount(void) are not same as GetEmployeeCount(). The details will be discussed in next chapter.

Executing DAME on this file produces files: CountDB.cpp and CountDB.hpp.

            shell> dame simple.dame
            DAME - Database Access Made Easy 1.0
            shell> ls Count*
            CountDB.cpp  CountDB.hpp
            shell>
        

Accessible Interfaces In CountDB

The way CountDB is written we have only the following interfaces generated:

            class CountDB {
               CountDB (Dame::DatabaseIf* db) ;
               ...
               template<Iterator>
               void GetEmployeeCount(Iterator it) ;
            }
            

So we can create a CountDB object by passing its constructor a DatabaseIf pointer and then use the GetEmployeeCount function to access the data. How do we get a DatabaseIf object? The next section explains that part.

Creating A DatabaseIf Object

DAME tries to be generic. All the code generated by DAME makes use of interface objects. The gateway to the database access classes in DAME is DatabaseIf. DAME support libraries for C++ provides mechanisms for creating the DatabaseIf objects. You can create a OracleDatabaseIf by using the following code fragment.

example.cpp

            #include "dame/oradatabase.hpp"
            ...
            char *user = "scott" ;
            char *password = "tiger" ;
            char *database = "dame" ;
            Dame::DatabaseIf*   db = new Dame::Oracle::OraDatabase (user, password, database) ;
            

Similarly for Postgresql:

example.cpp

            #include "dame/pgdatabase.hpp"
            ...
            char *user = "scott" ;
            char *password = "tiger" ;
            char *database = "dame" ;
            Dame::DatabaseIf*   db = new Dame::Postgres::PgDatabase (user, password, database) ;
            

What is Iterator?

Now that we understand how we can create a pointer to DatabaseIf we are one step closer to using the CountDB class. Before we can make use of GetEmployeeCount we need to understand what the template parameter Iterator is.

When the function GetEmployeeCount is called, in turn this function calls the Iterator object using the operator () and passing the return value (in this case it is Count ie. int). You can do any thing with the value as you like and return back to the calling function GetEmployeeCount. Not really anything.. but most of the things.

So how do we create a Iterator object? If you are new to STL (I suggest that you get familiarized with STL anyhow, if not you are losing half the fun using C++), the following code fragment looks strange. But, it does what it needs to be done and get us the results:

example.cpp

            int
            Print (int value)
            {
                std::cout << "Number of Employees: " << value << std::endl ;
                return 0 ;
            }
            
            ...
                CountDB     cdb (db) ;
                cdb.GetEmployeeCount (std::ptr_fun (&Print)) ;
            ...
            

Putting It All Together

Putting all these things together here is our first program. A C++ preprocessor Macro controls whether the code is generated for Oracle™ or Postgresql.

example.cpp

				#include <unistd.h>
				#include <stdlib.h>

				#include <exception>
				#include <iostream>
				#include <iomanip>
				#include <vector>

				#include <dame/utility.hpp>
				#include "CountDB.hpp"

				#ifdef ORACLE
				#include "dame/oradatabase.hpp"
				#else
				#ifdef POSTGRES
				#include "dame/pgdatabase.hpp"
				#else
				#error "A database need to be defined"
				#endif
				#endif

				int
				Print (int value)
				{
					std::cout << "Total number of employee records: " << value << std::endl ;
					return 0 ;
				}

				int
				main(int argc, char *argv[])
				{
					char *user = "scott", *password = "tiger", *database = "dame" ;

					try {
				#ifdef ORACLE
						Dame::Oracle::OraDatabase db (user, password, database) ;
				#else
						Dame::Postgres::PgDatabase db (user, password, database) ;
				#endif
						CountDB                 edb (&db) ;
						edb.GetEmployeeCount (std::ptr_fun(&Print)) ;
					} catch (std::exception& e) {
						std::cerr << e.what() << std::endl ;
						exit (1) ;
					}
					exit (0) ;
				}