· Struct блок - блок, аналогичен table , с той разницей, генерирует только определения структур записей без определения самой таблицы.
· Enum блок – определение С++ енумераторов, используемых в определении таблицы.
· Code блок – блок сырого С++ кода встраимого непосредственного в результирующий файл.
Транслятор состоит из 3 основных частей лексики, семантики и пускового модуля, написанных на языке Perl .
Лексический анализатор создан с учетом этой грамматики и имеет следующий интерфейс.
Prepare(array of lines); // normal result ==0
token Next ();
Он поддерживает также препроцессирование на уровне вложений include .
Семантический анализатор состоит из API , вызываемых как обработчики событий (для интерфейса yapp указываются в определении грамматики).
Пусковой модуль является оболочкой для запуска синтаксического анализатора, с разбором входных параметров
Формат:
1)HibaseCompiler.pl [-f имя файла] [-p путь к hibase] [-d каталог, куда помещ. сген стаб]
2)program | HibaseCompiler.pl [-p путь к hibase] [-d каталог,куда помещ. сген стаб].
6.Пример работы программы
В качестве примера расмотрим следующее определение базы данных
Tables.def
code def top
{*
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <db_cxx.h>
#include "../hblib/consts.hh"
#include "../hblib/ll.hh"
#include "../hblib/utils.hh"
#include "../hblib/hdb.hh"
#include "tbmain.hh"
#include "dbmain.hh"
*}
option
{
file = "main";
namespace = "hb";
};
table supplier
{
char [12]name .!; // key uh; //unq,hash
char [40]desc;
};
table thing
{
supplier+ tsupplier; // внешняя ссылка
char [12]name .!; // key uh; //unq,hash
char [40]desc;
};
end
В результате работы транслятора получаем 3 файла: файл описания структур записей таблиц, файл определения самих таблиц и базы и файл ее реализации:
hbmain.hh
namespace hb{
using namespace hb;
class mainEnv;
struct supplierKey
{
db_recno_t key;
inline void Export(FILE* f);
inline void Import(char*,uint);
supplierKey(const db_recno_t& key_temp);
supplierKey(){}
}__attribute__ ((packed));
struct supplierVal
{
char name[12];
char desc[40];
inline void Export(FILE* f);
inline void Import(char*,uint);
supplierVal(char* name_temp,char* desc_temp);
supplierVal(){}
}__attribute__ ((packed));
class qsupplier: public hbTable<supplierKey,supplierVal>{
mainEnv& menv;
public:
qsupplier(mainEnv&);
inline void RefInit();
static void GetRef_supplier(uint, char* ,char* , db_recno_t*&, uint&);
static int qsupplier::idx_name(Db *db,const Dbt* pk,const Dbt* pv,Dbt* fv);
};
struct isupplier_name
{
char name[12];
char* Getname(){return name;}
isupplier_name(char* name_temp);
}__attribute__ ((packed));
//------------------------------------------------------------------------------
struct thingKey
{
db_recno_t key;
inline void Export(FILE* f);
inline void Import(char*,uint);
thingKey(const db_recno_t& key_temp);
thingKey(){}
}__attribute__ ((packed));
struct thingVal
{
db_recno_t tsupplier;
char name[12];
char desc[40];
inline void Export(FILE* f);
inline void Import(char*,uint);
thingVal(const db_recno_t& tsupplier_temp,char* name_temp,char* desc_temp);
thingVal(){}
}__attribute__ ((packed));
class qthing: public hbTable<thingKey,thingVal>{
mainEnv& menv;
public:
qthing(mainEnv&);
inline void RefInit();
static void GetRef_thing(uint, char* ,char* , db_recno_t*&, uint&);
static int qthing::idx_name(Db *db,const Dbt* pk,const Dbt* pv,Dbt* fv);
};
struct ithing_name
{
char name[12];
char* Getname(){return name;}
ithing_name(char* name_temp);
}__attribute__ ((packed));
//------------------------------------------------------------------------------
};
dbmain.hh
namespace hb{
using namespace hb;
enum idxNames{
dbn_supplier_name = 0, dbn_thing_name = 0};
class mainEnv;
class mainEnv:public hbEnv{
public:
mainEnv(const char*,ushort flt = LL_DEBUG, Log* LogObj1 = 0);
qsupplier& tsupplier;
qthing& tthing;
};
};
dbmain.cc
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <db_cxx.h>
#include "../hblib/consts.hh"
#include "../hblib/ll.hh"
#include "../hblib/utils.hh"
#include "../hblib/hdb.hh"
#include "tbmain.hh"
#include "dbmain.hh"
//#include <stdio.h>
//#include <stdlib.h>
//#include <time.h>
//#include <string.h>
//#include <stdarg.h>
//#include <pthread.h>
//#include <unistd.h>
//#include <dirent.h>
//#include <ctype.h>
//#include <sys/types.h>
//#include "../hibase/consts.hh"
//#include "../hibase/ll.hh"
//#include "../hibase/hdb.hh"
//#include "myconst.hh"
//#include "dbmain.hh"
namespace hb{};
using namespace hb;
namespace hb{};
using namespace hb;
#define NUMDB 2
enum maindbNames{
dbnsupplier = 0,dbnthing};
static hbInit tblIndexes[]={
{ "supplier::name","supplier.i","name",DB_HASH,0,0,0,&qsupplier::idx_name, 0, 0 },
{ "thing::name","thing.i","name",DB_HASH,0,0,0,&qthing::idx_name, 0, 0 }
};
static hbInit tblInits[]={
{"supplier","supplier.q",0,DB_QUEUE,0,1, tblIndexes + 0 , 0, &qsupplier::GetRef_supplier, 0},
{"thing","thing.q",0,DB_QUEUE,0,1, tblIndexes + 1 , 0, &qthing::GetRef_thing, 1}
};
envInit mainEnvInit={
NUMDB,
"$Id: tblproc.pm,v 1.35 2004/01/10 23:57:48 bora Exp $"
};
qsupplier::qsupplier(mainEnv& env): hbTable<supplierKey,supplierVal>(env,tblInits[dbnsupplier]), menv(env)
{}
void qsupplier::RefInit()
{
}
void qsupplier::GetRef_supplier(uint num, char* key,char* val, db_recno_t*& refs, uint& ref_count)
{
supplierKey *key1 = (supplierKey*)key;
supplierVal *val1 = (supplierVal*)val;
}
void supplierKey::Export(FILE* f)
{
fprintf(f,"%d",key);
}
void supplierKey::Import(char* buf, uint len)
{
int j,num, i = 0;
char temp;
{j = i;for(;i<len;i++)if(buf[i]==',' || buf[i]=='}')break;}
temp = buf[i];buf[i] = '\0';sscanf(buf+j,"%d",&key);
buf[i] = temp;
i++;
}
supplierKey::supplierKey(const db_recno_t& key_temp)
{
memset(this,0,sizeof(*this));
key = key_temp;
}
void supplierVal::Export(FILE* f)
{
fprintf(f,"{");
CharArrInToStr(f,name,12);
fprintf(f,"}");
fprintf(f,",");
fprintf(f,"{");
CharArrInToStr(f,desc,40);
fprintf(f,"}");
}
void supplierVal::Import(char* buf, uint len)
{
int j,num, i = 0;
char temp;
if(buf[i++] !='{')
throw hbExcp (3, LL _ CRITICAL ,0,"Ошибка импорта: +указатель на таблицу = 0.");
j = i;
for(;i<len;i++)
{
if (buf[i] == '}' && buf[i-1]!='\')
break;
}
StrToCharArr(buf+j,i-j,name,12);
i+= 2;
if(buf[i++] !='{')
throw hbExcp (3, LL _ CRITICAL ,0,"Ошибка импорта: +указатель на таблицу = 0.");
j = i;
for(;i<len;i++)
{
if (buf[i] == '}' && buf[i-1]!='\')
break;
}
StrToCharArr(buf+j,i-j,desc,40);
i+= 2;
}
supplierVal::supplierVal(char* name_temp,char* desc_temp)
{
memset(this,0,sizeof(*this));
strncpy(name,name_temp, sizeof(name));
strncpy(desc,desc_temp, sizeof(desc));
}
isupplier_name::isupplier_name(char* name_temp)
{
memcpy(name,name_temp,sizeof(name));
}
int qsupplier::idx_name(Db *db,const Dbt* pk,const Dbt* pv,Dbt* fv)
{
supplierVal *v= (supplierVal*)(pv->get_data());
fv->set_data(v->name);
fv->set_size(sizeof(isupplier_name));
return 0;
}
//------------------------------------------------------------------------------
qthing::qthing(mainEnv& env): hbTable<thingKey,thingVal>(env,tblInits[dbnthing]), menv(env)
{}
void qthing::RefInit()
{
ref.reftables[0].type = '+';
ref.reftables[0].reftable = &menv.tsupplier;
}
void qthing::GetRef_thing(uint num, char* key,char* val, db_recno_t*& refs, uint& ref_count)
{
thingKey *key1 = (thingKey*)key;
thingVal *val1 = (thingVal*)val;
if(num==0)
{
refs = &val1->tsupplier; ref_count = 1;
}
}
void thingKey::Export(FILE* f)
{
fprintf(f,"%d",key);
}
void thingKey::Import(char* buf, uint len)
{
int j,num, i = 0;
char temp;
{j = i;for(;i<len;i++)if(buf[i]==',' || buf[i]=='}')break;}
temp = buf[i];buf[i] = '\0';sscanf(buf+j,"%d",&key);
buf[i] = temp;
i++;
}
thingKey::thingKey(const db_recno_t& key_temp)
{
memset(this,0,sizeof(*this));
key = key_temp;
}
void thingVal::Export(FILE* f)
{
fprintf(f,"%d",tsupplier);
fprintf(f,",");
fprintf(f,"{");
CharArrInToStr(f,name,12);
fprintf(f,"}");
fprintf(f,",");
fprintf(f,"{");
CharArrInToStr(f,desc,40);
fprintf(f,"}");
}
void thingVal::Import(char* buf, uint len)
{
int j,num, i = 0;
char temp;
{j = i;for(;i<len;i++)if(buf[i]==',' || buf[i]=='}')break;}
temp = buf[i];buf[i] = '\0';sscanf(buf+j,"%d",&tsupplier);
buf[i] = temp;
if ( tsupplier == 0) throw hbExcp (3, LL _ CRITICAL ,0," Ошибка импорта: +указатель на таблицу = 0. ");
i++;
if(buf[i++] !='{')
throw hbExcp (3, LL _ CRITICAL ,0," Ошибка импорта: не могу распарсить строку.");
j = i;
for(;i<len;i++)
{
if (buf[i] == '}' && buf[i-1]!='\')
break;
}
StrToCharArr(buf+j,i-j,name,12);
i+= 2;
if(buf[i++] !='{')
throw hbExcp (3, LL _ CRITICAL ,0," Ошибка импорта: не могу распарсить строку. ");
j = i;
for(;i<len;i++)
{
if (buf[i] == '}' && buf[i-1]!='\')
break;
}
StrToCharArr(buf+j,i-j,desc,40);
i+= 2;
}
thingVal::thingVal(const db_recno_t& tsupplier_temp,char* name_temp,char* desc_temp)
{
memset(this,0,sizeof(*this));
tsupplier = tsupplier_temp;
strncpy(name,name_temp, sizeof(name));
strncpy(desc,desc_temp, sizeof(desc));
}
ithing_name::ithing_name(char* name_temp)
{
memcpy(name,name_temp,sizeof(name));
}
int qthing::idx_name(Db *db,const Dbt* pk,const Dbt* pv,Dbt* fv)
{
thingVal *v= (thingVal*)(pv->get_data());
fv->set_data(v->name);
fv->set_size(sizeof(ithing_name));
return 0;
}
//------------------------------------------------------------------------------
mainEnv::mainEnv(const char *path,ushort flt, Log* LogObj1):hbEnv(path,mainEnvInit,flt,LogObj1),
tsupplier(* (new qsupplier(*this))),
tthing(* (new qthing(*this)))
{
dbs[dbnsupplier] = &tsupplier;tsupplier.RefInit();
dbs[dbnthing] = &tthing;tthing.RefInit();
}
Файл пример описан так
int main ( void )
{
mainEnv env ("./DataBase/");
//создаем базу, то есть формируем необходимые файлы для всех таблиц
env.Init(bexcp(16,"main","example.cc",3,LL_DEBUG));
env.Close(bexcp(16,"main","example.cc",3,LL_DEBUG));
env.ImportDB(bexcp(16,"main","example.cc",3,LL_DEBUG),"./Export1.ex");
env.ExportDB(bexcp(16,"main","example.cc",3,LL_DEBUG),"./Export.ex");
// проверяем на индексную целостность
env.CheckForIdx(bexcp(16,"main","example.cc",3,LL_DEBUG));
// проверяем на ссылочную целостность
env.CheckForRef(bexcp(16,"main","example.cc",3,LL_DEBUG));
env . OpenTDSMode (); //открываем ее в нормальном транзакционном режиме
try
{
hbTxn tx(env);
tx.Start();
supplierKey key = {1} ;
supplierVal val = {"Boris","Boss"};
env.tsupplier.Put(&tx,&key,&val);
thingKey key = {1} ;
thingVal val = {1,"Computer","best"};
env.tthing.Put(&tx,&key,&val);
tx.commit();
}
catch(hbExcp& excp)
{
cout<<excp.what();
}
env.Close();
return 0;
}
7.Заключение
На сегодняшний день навигационно-сетевые базы вновь приобрели свою актуальность. Это обуславливается, главным образом, их очень высокой скоростью работы, даже, несмотря на сложность понимания для неквалифицированного специалиста. Чтобы облегчить работу программисту с такой базой средствами BerkeleyDB к ней был введен генератор объектно-ориентированного интерфейса. Это позволило качественно улучшить скорость разработки на С++ и повысить уровень абстракции работы с ней.
8.Список используемой литературы:
1) http :// www . sleepycat . com – официальный сайт компании –разработчика BerkeleyDB
2) The Object Data Standard ODMG 3.0. New York, MK, 2002.
3) Gamma E., Helm R., Johnson R., Vlissides J. Design Patterns: Elements of reusable object-oriented software, Reading, MA: Addison-Westley, 1995.
4) Герберт Шилдт. Полный справочник по С. М., Вильямс, 2002.