C++ API & Espresso C++

The Espresso API offers a superset of the OpenBase API to insulate developers from having to always construct SQL. The Espresso API layer takes care of all the SQL, record locking, data encoding and all database access. It is an abstraction layer. At the same time, the Espresso API does not prevent you from writing your own SQL.

Features Include:

- A BLOB/object faulting mechanism that automatically fetches BLOB data when requested. This improves performance when requesting large data sets which include BLOB/object data.

- A relationship faulting mechanism allowing users to ask for records in relating tables. The API layer takes care of the relationships.

- Optimistic and Pessimistic locking seamlessly supported.

- Fully compatible with all transaction modes.

The example program discussed in this chapter uses the WOMovies database.

Introduction

The Espresso C++ API offers a C++ wrapper around all of the traditional OpenBase API routines as well as DBEntity and DBRecord classes for managing database information. The DBEntity class gives you access to the database schema and relationships. Instances of the DBEntity class offer schema definitions and management of individual tables. Instances of DBRecord allow you to interact with rows of data.

Before you begin, you need to include the the following headers in your project:

#include "OpenBaseChannel.h"
#include "DBEntity.h"
#include "DBRecord.h"

You need to also establish a connection to the database using the OpenBase C++ API. Here is an example:

#define DATABASE_NAME "WOMovies"
#define DATABASE_HOST "127.0.0.1"
#define DATABASE_LOGIN "admin"
#define DATABASE_PASSWORD ""
// connect to the database
OpenBaseChannel *channel = new OpenBaseChannel;
if (!channel->connectToDatabase(DATABASE_NAME, DATABASE_HOST, DATABASE_LOGIN, DATABASE_PASSWORD, &returnCode)) { printf("%s\n", channel->connectErrorMessage());
return -1;

Schema Information

Here is some example code of how to get information about the schema using the WOMovies database. For those who know C++ this should be fairly easy to see how this works.

// list the tables in the database NSArray of names printf("Tables:\n");
DBEntity::tableNames(channel)->Print();
// get the movie entity
testEntity = DBEntity::entity("MOVIE",channel);
// print the columns
printf("columns for MOVIE = %s\n", testEntity->columns()->toString() );
// print the valid relationships printf("relationships for MOVIE = %s\n", testEntity->relationshipNames(channel)->toString() );

Here is what each of these routines actually returns:

- DBEntity::tableNames(channel) returns an DBArray of table names.

- testEntity->columns() returns an DBArray of column names.

- testEntity->relationshipNames(channel) returns an DBArray of relationship names.

Fetching Records

What most folks want to do is fetch a bunch of records and do something useful with them. There are several "selectRecordsWith:" methods which offer a variety of options to choose from. The one below selects all records where the TITLE column starts with the letter "L". Results are ordered by TITLE. A MaxReturned value of 0 means that all results are returned. Specifying a number greater than 0 would limit the number returned. "selectRecordsWith:"returns an NSArray of DBRecord objects.

// find all the movie titles
records = testEntity->selectRecords ("TITLE like 'L* '", "TITLE", 0, channel);

Here is a complete list of similar methods for selecting data:

In DBEntity:

static DBArray* recordsForQuery ( const char* selectQuery, OpenBaseChannel* channel );
DBRecord* selectRecord ( const char* keyValue, OpenBaseChannel* channel );
DBArray* selectAllRecords ( OpenBaseChannel* channel );
DBArray* selectRecords ( const char* whereStatement, const char* orderBy, int maxReturned,
OpenBaseChannel* channel );
DBArray* selectRecords ( const char* whereStatement, const char* orderBy, int maxReturned,
bool forUpdate, OpenBaseChannel* channel );
DBArray* selectRecords ( const char* whereStatement, const char* orderBy, int rangeStart,
int rangeEnd, bool forUpdate, OpenBaseChannel* channel );

Getting Values

Next we may want to loop through the records and view some of the values. In this example we demonstrate the stringForColumn method. However, there are a number of accessor methods offered for all the different data types. The API will automatically convert the information to the destination type.

The "columnForColumnName" method looks up the column name in a dictionary and returns a column number. This number is used identify the column in the DBRecord.

// print the record values
for (ct=0; ct < records->count(); ct++) {
recordObject = (DBRecord*) records->objectAtIndex(ct);
printf("      \n");
printf("MOVIE = %s\n", recordObject->stringForColumn( recordObject->columnForColumnName("TITLE") ) ); printf("      \n");
// now for each movie I want to drill down and get related records from the roles table
relatedRecords = recordObject->recordsForRelationship("roles",channel);
// NOTE: to get the colums and tablename you simple have to get the entity of one of the records in this Array. See examples above.

Here is a complete list of the accessor methods used to get information:

// getting string values (includes BLOBS) const char* stringForColumn ( int column );
// getting data values (includes BLOBS)
unsigned char* dataForColumn ( int column, int* length );
// getting numerical values
bool booleanValueForColumn ( int column ); int intValueForColumn ( int column );
long longValueForColumn ( int column );
double doubleValueForColumn ( int column );
long long longlongValueForColumn ( int column );
// checking for NULL value
bool isColumnNull ( int column );

Accessing Records Through Relationships

Each MOVIE has several actors. As we loop through each MOVIE record we might also want to select the related records from the MOVIE_ROLES table. To do this we need to call the DBRecord's "recordsForRelationship:" method which returns a list of the related records relative to the specific record we are referencing. In the example below we get the roles and loop through each.

// now for each movie I want to drill down and get related records from the roles table
relatedRecords = recordObject->recordsForRelationship("roles",channel);
// NOTE: to get the colums and tablename you simple have to get the entity of one of the records in this Array. See examples above.
// loop through related records
for (ct2=0; ct2 < relatedRecords->count(); ct2++) {
relatedRecord = (DBRecord*) relatedRecords->objectAtIndex(ct2);
printf("ROLE NAME = %s\n", relatedRecord->stringForColumn( relatedRecord->columnForColumnName("ROLE_NAME") ) ); }

Updating the Values

The next thing we are going to do in this example is update each movie title by adding the word "foo" at the end. First we create a new string using the original value, and then we call the setString:forColumn: method to set the value.

void setStringForColumn ( const char* value, int column ); // setting string values (includes BLOBS)
sprintf ( s, "%s foo", recordObject->stringForColumn(recordObject->columnForColumnName("TITLE")) );
    recordObject->setStringForColumn ( s,
   recordObject->columnForColumnName("TITLE") );

Here is a complete list of methods that can be used to set values:

void setDataForColumn ( unsigned char* value, int length, int column ); // setting data values (includes BLOBS)
// setting numerical values
void setBooleanValueForColumn ( bool value, int column );
void setIntValueForColumn ( int value, int column ); void setLongValueForColumn ( long value, int column ); void setDoubleValueForColum ( double value, int column );
   void setLongLongValueForColumn ( LONGLONG value, int column );

Inserting New Rows

DBRecord* newRecord ( OpenBaseChannel* channel );

Inserting new rows are accomplished through the DBEntity object using the "newRecord" method. Creating the record will automatically create a new primary key. However, the record will not physically be inserted into the table until you save changes.

newRecord = newRecord ( OpenBaseChannel* channel ); newRecord->setStringForColumn ( "My Family Movie", newRecord->columnForColumnName("TITLE") );

Committing the Changes to the Database

The final step is to commit the changes. Since this new API is an extension of our existing API, the software developer has a lot of control over how this happens. For instance, if you would like to put everything inside a transaction (as we did below) you can do that. You can also validate business rules or perform other operations using the low-level API as part of the same transaction.

You need to call saveAllChangesWithConnection: for each entity that has changes. You can also optionally tell individual records to save.

channel-> beginTransaction(); testEntity->saveAllChanges (channel); channel-> commitTransaction();

Using Editing Contexts

An editing context is a container which keeps track of all the changes that are made across many tables and allows you to commit those changes all at once. The DBEntity class also keeps track of the changes, as demonstrated by the testEntity above. However, there may be cases where you want to keep track of changes made beyond a single table and execute those changes in the order they were made by the application.

Here is how you initialize a global editing context and get a handle on it.

DBEditingContext *contextObject = DBEntity::globalEntityCache();

After initializing the editing context you can perform changes to the records. When you are finished you can save the changes to the database as follows:

channel-> beginTransaction(); contextObject->saveAllChanges (channel); channel-> commitTransaction();

If you are using a multi-threaded application it is important to keep track of the editing contexts for each thread and set the editing context before each change using semaphores to keep the context from being reset by a different thread.

Here is how you create a new entity cache.

DBEntity::setGlobalEntityCache(NULL);
[DBEntity setGlobalEntityCache:NULL]; contextObject = DBEntity::globalEntityCache();

This is how you set the global entity cache once it is created.

DBEntity::setGlobalEntityCache(contextObject);

Memory Management

The DBObject class implements a reference counting mechanism for managing the life cycle of objects. It is very similar to Apple's Objective-C mechanism.

The general idea is that you pass around object pointers freely, without worrying about memory. Only when you want to hold onto an object for a while do you lock it down by 'retaining' it. An object can be retained multiple times, by different objects and in different pieces of code.

An object is released by an object or a piece of code when it is no longer needed. When the last release is performed on an object, there are no more references to it and it is deleted. This cascades, and so the releasing of a single object can cause many objects to be deleted.

The Simple Case

When you create an object with the 'new' operator, you get an implicit 'retain' that you will have to ultimately release/autorelease when you are done using the object.

This is valid usage pattern:

SomeClass* obj = new SomeClass;
obj->autorelease(); // i don't need this object any more DBObject::garbageCollection();

Don't use the 'delete' operator.

delete obj; // do not use the 'delete' operator

The object is deleted automatically by the memory management system when there are no more references to it.

Your classes should implement a destructor to properly cleanup.

SomeClass::~SomeClass()
{
if ( other != nil ) other->autorelease();

Release vs Autorelease

In general, you should use autorelease(). The method release() can easily lead to problematic situations. This is also true with Objective-C, but Apple underplays the possible problems. You should only use release() when you have a memory situation that needs to be managed tightly, and then you must know what you are doing.

Passing Objects Around

When your code gets an object (other than creating it with 'new'), it is NOT yours to keep.

SomeClass* obj = another->GetMeTheObject();

You have the object in hand but it is not yours to keep forever. You are guaranteed it will be valid for a short while but not for long. I call this a 'temporary' object. In fact, it may or may not be temporary but you don't know that. So from your perspective, it is temporary.

How long do temporary objects last? The best way to think about it is "until you return from the method or routine". Or until you perform garbage collection (more later).

If you do want to keep the temporary object (hold onto it for later), you have to retain it.

obj->retain();

Now it is yours until you release it. If you forget to release it, that is a memory leak.

obj->autorelease();
obj = nil; // this is a good habbit

If you have a method that wants to return an object, you would autorelease it after creating it. If your caller wants to hold onto it, then it can retain it but that is not your responsibility. The golden rule is "be responsible only for yourself" ('yourself' being a method, routine or class).

SomeClass* SomeClass::GetMeTheObject()
SomeClass* obj = new SomeClass; // with an implicit retain obj->autorelease();
return obj;
}

Set and Get methods:

This is the standard pattern for Set and Get methods.

SomeClass* SomeClass::GetOther ()
{
return other; // 'other' is an object instance variable
}
void SomeClass::SetOther ( SomeClass* newOther )
{
if ( other != nil )
other->autoreleaes();
other = newOther;
other->retain();
}

Garbage Collection

Autoreleased objects are released with this command.

DBObject::garbageCollection();

Releasing an object will delete the object if the reference count falls to zero.

When an object is released for the last time (i.e. its reference count is decremented to zero), the object is deleted.

This is an invalid usage pattern:

SomeClass* obj = new SomeClass;
obj->autorelease();
DBObject::garbageCollection();
obj->Print(); // <--- obj has been deleted so this will crash

This is valid:

SomeClass* obj = new SomeClass; // with an implict 'retain' DBObject::garbageCollection(); // does not delete 'obj' because it was retained
obj->Print(); // this is fine
obj->autorelease();

You want to perform garbage collection as often as possible to keep your applications' memory usage down. But you have to be careful, because garbage collection deletes objects.

SomeClass* obj = FindTheObject (); DBObject::garbageCollection(); // this may or may not delete ' obj ' , it depends

Usually, you would put garbage collection at high levels in your program i.e. in an event dispatcher. In the case of a 'linear' program, you can perform garbage collection after each step in your program.

Whenever you perform garbage collection, you have to be concerned about the code that called you, and all the way up the stack. If higher levels are depending on 'temporary' objects, then they are going to be in a world of pain.

Collection Objects

Two collection objects are provided, DBArray and DBDictionary. They both retain all objects that they contain. They autorelease those objects when the objects are removed or replaced.

Debugging Memory Problems

Your code can have too few calls to release(), in which case you have a memory leak. Or it can have too many calls to release(), in which case you overwrite memory and will probably crash your program.

DBObject has two methods for helping you debug memory problems that you might have.

1. You can trace memory operations with the static method:

DBObject::setTraceMemory (true);

This is the kind of tracing you will see:

MEMORY retain d68d0/_DBValue rc 5 MEMORY new da340/DBObject rc 1 MEMORY new da360/DBObject rc 1 MEMORY retain da360/_DBValue rc 2 MEMORY retain d7070/_DBValue rc 6 MEMORY release da360/_DBValue rc 1 MEMORY autorelease de7c0/_DBValue rc 1
MEMORY release dc940/_DBValue rc 0 and delete
MEMORY garbageCollection 252 objects

You can see your reference counts climb and fall. If your reference counts don't get down to zero when you expect them to, then you have found a memory leak.

2. If your program is crashing because of too many calls to release, then you skip all delete operations.

DBObject::setSkipDelete (true);

This will prevent crashing by never deleting objects and therefore using up lots of memory. But then you can look at the pattern of memory usage and spot bad patterns. And when your code does release an object more than it should, you'll get a nice error message instead of a crash.

OpenBaseAdmin .h

//================================================================================
//    Functions
//================================================================================
//--------------------------------------------------------------------------------
//    Connecting and Disconnecting
//--------------------------------------------------------------------------------
    // connecting to the openexec process
    OpenBaseAdminConnection* oba_newAdminConnection(const char *hostName);
    // destroying the connection to the openexec process
    void oba_deallocAdminConnection(OpenBaseAdminConnection* admin_conn);
//--------------------------------------------------------------------------------
//    performing admin functions with the openexec process
//--------------------------------------------------------------------------------
    const char *oba_databaseHostInfoString(OpenBaseAdminConnection* admin_conn);
    // returns "hostname|ethernetaddress|ipaddress|OpenBaseVersion|Platform"
    int oba_checkStatesChanged(OpenBaseAdminConnection* admin_conn);
    // returns 1 or 0 depending on whether any of the states have changed
    // since the last call

    int oba_databaseStateList(OpenBaseAdminConnection* admin_conn,
            const char **states, const char **alerts);

    // The state string gives a list of databases that have state information
    // and their corresponding state.
    // Databases that are not running will not be listed.
    //
    // states = "databaseName:stateString|databaseName:stateString"
    //  -- stateString can contain % done using the format:  
            stateString = "cleanup%49"
    //  -- other stateStrings include: running, starting, stopping
    //
    // Alerts are used for alerting the user of an error condition in
    // the log.  Alerts are conveyed in the following format:
    //
    // alerts = "databaseName:alert%updateNumber|databaseName:alert%updateNumber"
    //  -- alert can be any of: none, warning, error, severe
    //  -- updateNumber is a timestamp which changes only when there is a
    // new error in the log since the last time we checked.
    //
    OpenBaseDatabaseList* oba_getDatabaseList(OpenBaseAdminConnection* admin_conn,
            const char* read_password);
    //    get the database list
    //    caller must deallocate result with oba_deallocDatabaseList

    void oba_deallocDatabaseList(OpenBaseDatabaseList* database_list);
    //    free the result

    int oba_startDatabase(OpenBaseAdminConnection *adminConnection,
            const char *databaseName, const char *password);
    int oba_stopDatabase(OpenBaseAdminConnection *adminConnection,
            const char *databaseName, const char *password);

    int oba_newDatabase(OpenBaseAdminConnection *adminConnection,
        const char *databaseName, const char *password);
    int oba_duplicateDatabase(OpenBaseAdminConnection *adminConnection,
        const char *databaseName, const char *duplicatedName,  
        const char *password);
    int oba_renameDatabase(OpenBaseAdminConnection *adminConnection,
        const char *databaseName, const char *newDatabaseName,
        const char *password);
    int oba_moveDatabase(OpenBaseAdminConnection *adminConnection,
        const char *sourceDatabaseName, const char *sourcePassword,
        const char *targetHost, const char *targetHostPassword);
    int oba_deleteDatabase(OpenBaseAdminConnection *adminConnection,
        const char *databaseName, const char *password);
    int oba_checkHostPassword(OpenBaseAdminConnection *adminConnection,
        const char *password);
    int oba_setHostPassword(OpenBaseAdminConnection *adminConnection,
        const char *oldpassword, const char *newpassword);

    int oba_checkReadPassword(OpenBaseAdminConnection *adminConnection,
        const char *password);
    int oba_setReadPassword(OpenBaseAdminConnection *adminConnection,
        const char *oldpassword, const char *newpassword);
    int oba_encodingForDatabase(OpenBaseAdminConnection *adminConnection,
        const char *database, char **encoding, const char *password);
    int oba_setEncodingForDatabase(OpenBaseAdminConnection *adminConnection,
        const char *database, const char *encoding, const char *password);
    int oba_databaseDescription(OpenBaseAdminConnection *adminConnection,
        const char *databaseName, char **databaseDescription,
        char **bubbleColor, char **size);
    int oba_setDatabaseDescription(OpenBaseAdminConnection *adminConnection,
        const char *databaseName, const char *password,
        const char *description, const char *bubbleColor);
    const char *oba_autoStartDatabaseList(OpenBaseAdminConnection *adminConnection,
        const char *password);
    int oba_setAutoStartDatabase(OpenBaseAdminConnection *adminConnection,
        const char *databaseName, const char *password, const char *yn);
    const char *oba_getLogFile(OpenBaseAdminConnection *adminConnection,
        const char *databaseName, const char *password);
    const char *oba_getServerMacAddress(OpenBaseAdminConnection *adminConnection);
    int oba_getDatabasePreferences(OpenBaseAdminConnection *adminConnection,
        const char *databaseName, const char *password,
        const char **sortChars,
        const char **sortCharsCaps,
        const char **moneyPostfix,
        const char **moneyPrefix,
        const char **date,
        const char **time,
        const char **logSQL,
        const char **logSQLFile,
        const char **compressedBackup,
        const char **compressedBackupTime,
        const char **compressedBackupDay,
        const char **compressedBackupDirectory,
        const char **asciiBackup,
        const char **asciiBackupTime,
        const char **asciiBackupDay,
        const char **asciiBackupDirectory,
        const char **createClientMirror,
        const char **createMasterMirror,
        const char **clientClusterName,
        const char **masterClusterName);
int oba_setDatabasePreferences(OpenBaseAdminConnection *adminConnection,
        const char *databaseName, const char *password,
        const char *sortChars,
        const char *sortCharsCaps,
        const char *moneyPostfix,
        const char *moneyPrefix,
        const char *date,
        const char *time,
        const char *logSQL,
        const char *logSQLFile,
        const char *compressedBackup,
        const char *compressedBackupTime,
        const char *compressedBackupDay,
        const char *compressedBackupDirectory,
        const char *asciiBackup,
        const char *asciiBackupTime,
        const char *asciiBackupDay,
        const char *asciiBackupDirectory,
        const char *createClientMirror,
        const char *createMasterMirror,
        const char *clientClusterName,
        const char *masterClusterName,
        const char *dbSerialNumber,
        const char *dbAuthorization);

int oba_getInitializationForCluster(OpenBaseAdminConnection *adminConnection,
        const char *databaseName, const char *clusterName,
        char **targetDatabase, char **targetHost, char **targetUser,
        char **targetPassword, int *frequency, const char *password);
int oba_setInitializationForCluster(OpenBaseAdminConnection *adminConnection,
        const char *databaseName, const char *clusterName,
        const char *targetDatabase, const char *targetHost,
        const char *targetUser, const char *targetPassword,
        int frequency, const char *password);
int oba_createClusterFile(OpenBaseAdminConnection *adminConnection,
        const char *databaseName, const char *clusterName, const char *password);
int oba_removeCluster(OpenBaseAdminConnection *adminConnection,
        const char *databaseName, const char *clusterName, const char *password);
int oba_clearCluster(OpenBaseAdminConnection *adminConnection,
        const char *databaseName, const char *clusterName, const char *password);
int oba_encryptionForDatabase(OpenBaseAdminConnection *adminConnection,
        const char *databaseName, const char *password);
int oba_setEncryptionForDatabase(OpenBaseAdminConnection *adminConnection,
        const char *databaseName, const char *password, int yn);
int oba_portNumberForDatabase(OpenBaseAdminConnection *adminConnection,
        const char *databaseName, const char *password);
int oba_setPortNumberForDatabase(OpenBaseAdminConnection *adminConnection,
        const char *databaseName, const char *password, int port);
int oba_notificationForDatabase(OpenBaseAdminConnection *adminConnection,
        const char *databaseName, const char *password);
int oba_setNotificationForDatabase(OpenBaseAdminConnection *adminConnection,
        const char *databaseName, const char *password, int notify);
int oba_distributedKeyForDatabase(OpenBaseAdminConnection *adminConnection,
        const char *databaseName, const char *password, int *databaseKey,
        int *multiplier);
int oba_setDistributedKeyForDatabase(OpenBaseAdminConnection *adminConnection,
        const char *databaseName, const char *password, int databaseKey,
        int multiplier);
int oba_transactionTimeout(OpenBaseAdminConnection *adminConnection,
        const char *databaseName, const char *password, int *trans_timeout,
        int *connect_timeout);
int oba_setTransactionTimeout(OpenBaseAdminConnection *adminConnection,
        const char *databaseName, const char *password, int trans_timeout,
        int connect_timeout);
int oba_isSimulationModeOnForDatabase(OpenBaseAdminConnection *adminConnection,
        const char *databaseName, const char *password) ;
int oba_setSimulationMode(OpenBaseAdminConnection *adminConnection,
        const char *databaseName, const char *password, int yn);
int oba_isNoDeleteModeOnForDatabase(OpenBaseAdminConnection *adminConnection,
        const char *databaseName, const char *password) ;
int oba_setNoDeleteMode(OpenBaseAdminConnection *adminConnection,
        const char *databaseName, const char *password, int yn);
int oba_isSafeSQLModeForDatabase(OpenBaseAdminConnection *adminConnection,
        const char *databaseName, const char *password) ;
int oba_setSafeSQLMode(OpenBaseAdminConnection *adminConnection,
        const char *databaseName, const char *password, int yn);
const char *oba_automaticTriggerFileForDatabase(
    OpenBaseAdminConnection *adminConnection, const char *databaseName,
    const char *password) ;
int oba_setAutomaticTriggerFileForDatabase(
    OpenBaseAdminConnection *adminConnection, const char *databaseName,
    const char *password, const char *filecontent);
int oba_restartProcesses(OpenBaseAdminConnection *adminConnection,
    const char *password);
void oba_setDebug(int debugOnOff) ;

DBArray.h

DBArray();
DBArray( int initialSize );
DBArray( DBArray* otherArray );
~DBArray();
const char* className() { return "DBArray"; }
bool isKindOfClassNamed(const char* className);
char* toString();
int count();
void addObject ( DBObject* object );
void removeObject ( DBObject* object );
void replaceObjectAtIndex ( DBObject* object, int index );
void removeAllObjects ();
DBObject* objectAtIndex (int index);
int indexOfObject ( DBObject* object ); // returns -1 if not found
bool containsObject ( DBObject* object );
// these two methods only used by garbage collection
void releaseAllObjects ();
void addObjectNoRetain ( DBObject* object );

DBEditingContext.h

DBEditingContext ();
virtual ~DBEditingContext ();
const char* className() { return "DBEditingContext"; }
bool isKindOfClassNamed(const char* className);
void addLockedRecord ( DBRecord* record );
void removeLockedRecord ( DBRecord* record );
bool saveAllChanges ( OpenBaseChannel* channel );
void releaseEdits ( OpenBaseChannel* channel );
void releaseEdit ( DBRecord* record, OpenBaseChannel* channel );

DBEntity.h

DBEntity();
DBEntity ( const char* tableName, DBArray* columnNames,  
        DBArray* matchingKeyNames );
/* debugging
DBObject* autorelease ();
void release ();
DBObject* retain ();
*/
virtual ~DBEntity ();
const char* className() { return "DBEntity"; }
bool isKindOfClassNamed(const char* className);
char* toString();
static DBEntity* entity ( const char* tableName, OpenBaseChannel* channel );
      // returns an entity object that is preconfigured to work with a table
      // these entity objects are cached
static void resetEntityCache ();
static DBArray* tableNames ( OpenBaseChannel* channel );
      // returns the table names in the database
static DBArray* relationshipsForTable ( const char* tableName,
        OpenBaseChannel* channel );
      // returns the relationship names which are relative to a particular entity
static DBArray* recordsForRelationship ( const char* relationship,
        DBRecord* recordObject,
                        OpenBaseChannel* channel );
      // fetches related records through a table
static DBArray* recordsForQuery ( const char* selectQuery,
        OpenBaseChannel* channel );
static DBArray* recordsForQuery ( const char* selectQuery,
        OpenBaseChannel* channel, DBEntity** entity );
double executionTime ();
void setExecutionTime ( double time );
static DBObject* NULL_VALUE();
      // NULL_VALUE is a global empty string which is used to identify NULL objects.
      // A NULL will always be this object.
DBArray* relationshipNames ( OpenBaseChannel* channel );
      // finds all the relationship paths which could be used from this entity
DBRecord* newRecord ( OpenBaseChannel* channel );
DBRecord* selectRecord ( const char* keyValue, OpenBaseChannel* channel );
DBArray* selectAllRecords ( OpenBaseChannel* channel );
DBArray* selectRecords ( const char* whereStatement, const char* orderBy,
        int maxReturned, OpenBaseChannel* channel );
DBArray* selectRecords ( const char* whereStatement, const char* orderBy,
        int maxReturned, bool forUpdate, OpenBaseChannel* channel );
DBArray* selectRecords ( const char* whereStatement, const char* orderBy,
        int rangeStart, int rangeEnd, bool forUpdate, OpenBaseChannel* channel );
int lockingType ();
void setLockingType ( int type );
void _addLockedRecord ( DBRecord* recordObject );
void _removeLockedRecord ( DBRecord* recordObject );
bool saveAllChanges ( OpenBaseChannel* channel );
void releaseEdits ( OpenBaseChannel* channel );
const char* tableName();
const char* columnName ( int columnNumber );
DBArray* columns (); // column names
DBArray* _columnObjects ();
int columnCount ();
const char* keyName ( int columnNumber );
const char* keyForColumnName ( const char* columnName );
const char* columnForKeyName ( const char* keyName );
int locationOfColumn ( const char* columnName );
int locationOfKey ( const char* keyName );
// EditingContext methods
static void initializeGlobalEditingContext();
static void setGlobalEditingContext ( DBEditingContext* editingContext );
static DBEditingContext* globalEditingContext();
// Entity cache
static void initializeGlobalEntityCache();
static void setGlobalEntityCache ( DBDictionary* entityCache );
static DBDictionary* globalEntityCache();
// these are so we know when to throw out the cache.
static void incrementSchemaVersion();
static int schemaVersion();

DBRecord.h

DBRecord ();
DBRecord ( DBEntity* entity, DBArray* recordValues, OpenBaseChannel* channel );
~DBRecord ();
const char* className();
bool isKindOfClassNamed(const char* className);
char* toString();
DBArray* recordsForRelationship ( const char* relationship, OpenBaseChannel* channel );
   // this method allows you to fetch through a relationship
   // see the DBEntity object on ways to get the relationships for an entity.
   // connection:(OpenBase *)connection;
DBEntity* entity();
   // the entity used to fetch this record.
//***************************************************
// getting the column location
//***************************************************
int columnForColumnName ( const char* colName );
int columnForKey ( const char* colName );
//***************************************************
// Setting and getting the native type value (private)
//***************************************************
DBObject* _nativeValueForColumn ( int column );
   // actually returns _DBValue*
void _setNativeValueForColumn ( DBObject* value, int column );
   // actually value is _DBValue*
//***************************************************
// ACCESSING VALUES
//***************************************************
bool isColumnNull ( int column );
   // checking for NULL value
// FIX ME // NSCalendarDate* dateValueForColumn ( int column );
   // getting a timestamp value
const char* stringForColumn ( int column ); // honors character encoding
   // getting string values (includes BLOBS)
unsigned char* dataForColumn ( int column, int* length );
   // getting data values (includes BLOBS) // ignores character encoding
// getting numerical values
bool booleanValueForColumn ( int column );
int intValueForColumn ( int column );
long longValueForColumn ( int column );
double doubleValueForColumn ( int column );
LONGLONG longlongValueForColumn ( int column );
// FIX ME // void setDateForColumn ( NSCalendarDate* value, int column );
   // setting timestamp values
void setStringForColumn ( const char* value, int column );
   // setting string values (includes BLOBS)
void setDataForColumn ( unsigned char* value, int length, int column );
   // setting data values (includes BLOBS)
// setting numerical values
void setBooleanForColumn ( bool value, int column );
void setIntegerForColumn ( int value, int column );
void setLongForColumn ( long value, int column );
void setDoubleForColumn ( double value, int column );
void setLongLongForColumn ( LONGLONG value, int column );
void _setLocked ();
void _setForUpdate();
bool hasUnsavedChanges ();
bool editRecord ( OpenBaseChannel* channel );
bool deleteRecord ( OpenBaseChannel* channel );
bool saveChanges ( OpenBaseChannel* channel );
void releaseEdit ( OpenBaseChannel* channel );

DBResultSet.h

DBResultSet ();
DBResultSet ( const char* entityName, const char* whereStatement,
    const char* orderBy, int cachedRecords, OpenBaseChannel* channel );
~DBResultSet ();
bool isKindOfClassNamed(const char* className);
bool refreshKeysOrderedBy ( const char* orderBy, OpenBaseChannel* channel );
const char* keyForPosition ( int position );
DBRecord* recordForKey ( const char* keyValue, OpenBaseChannel* channel );
DBRecord* recordAtPosition ( int position, OpenBaseChannel* channel );

OpenBaseChannel.h

OpenBaseChannel ();
virtual ~OpenBaseChannel ();
bool isKindOfClassNamed(const char* className);
char* toString();
const char* className();
void reallyDestroy(); // ignore this; for debugging
static void setDefaultTrace ( bool defaultTrace );
static bool defaultTrace ();
void setTrace ( bool yn );
bool trace ();
int connectToDatabase( const char* dbName,
              const char* dbHostName,
              const char* loginName,
              const char* passwordString,
              int* returnCode);
char* hostName();
const char* loginName();
char* password();
char* databaseName();
const char* softwareID ();
void setSoftwareID ( const char* id );
const char* clientName ();
void setClientName ( const char* name );
OpenBase* OpenBaseConnection();
int databaseEncoding();
int clientEncoding();
void setClientEncoding (int encoding);
void deallocConnection();
void invalidate();
int abortFetch();
int beginTransaction();
int commitTransaction();
int rollbackTransaction();
void bindDouble(double* var);
void bindBoolean(int *var);
void bindInt(int* var);
void bindLong(long* var);
void bindLongLong(int* var);
void bindString(char* var);
void bindBinary(char *var);
int bufferHasCommands();
char* commandBuffer();
void clearCommands();
const char* connectErrorMessage(); // DEPRECATED
const char* serverMessage();
void deallocBinary(const char* blob);
void deallocCursor(OpenBaseCursor * cursor);
void deallocResultData(OpenBaseResultData * resultData);
void deallocResultDataList(OpenBaseResultData * resultData);
const char* insertBinary(const char* data, int size);
int isColumnNULL(int col);
void makeCommand(const char* cmd);
void makeCommandLength(const char* cmd, int length);
void makeCommandAndEncode(const char *cmd);
void makeCommandLengthAndEncode(const char *cmd, int length);
void makeCommandConvertEncoding(const char *cmd);
int executeCommand();
OpenBaseCursor* retrieveCursor();
OpenBaseCursor *newResult();
OpenBaseResultData *newResultData();
int nextCursorRow(OpenBaseCursor *cursor);
int nextRow();
int preparedExecute();
int prepareParamsRequired();
int prepareStatement(const char* sqlstring);
int prepareSelectStatement(const char* sqlstring);
int prepareValuePosition();
int markRow(const char* anId, const char* tableName);
int markRowAlreadyMarkedByUser(const char* anId, const char* tableName,
        char* userName);
int removeMarkOnRow(const char* anId, const char* tableName);
int resultColumnCount();
char* resultColumnName(int col);
int resultColumnType(int col);
int resultReturned();
char* resultTableName(int col);
const char* retrieveBinary(const char* blobIdentifier, int* returnSize);
int rowsAffected();
const char* insertedRowid();
const char* uniqueRowIdForTable(const char* tblname);
const char* uniqueRowIdForTableColumn(const char* tblname, const char* colname);
int _widthForColumn(int col);
void _estimateColumnWidths();
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License