Приложение 3.
Пример организации простейшей СУБД на Турбо-Прологе
В последующем примере программы иллюстрируется, как реализуются новые предикаты, которые подобны assrtz и retract за исключением того, что получающаяся база данных содержится в файле, а не в оперативной памяти. Это расширяет возможности динамической базы данных, так как факты базы данных являются частью Пролог-программы и, следовательно, ограничиваются размером доступной оперативной памяти. При размещении базы данных в файлах единственным ограничением является размер доступного дискового пространства.
В программе предикаты dbassert(), dbdeletе() и dbroad() предназначены для записи, удаления и чтения данных вниз файла БД. Эти предикаты реализованы, используя индексный файл для записи позиций фактов, в файле данных. Каждая позиция представляется действительным числом, определяющим, где данный факт хранится относительно начала файла базы данных.
Предикат use() используется для задания имени файла рабочей БД и имени, соответствующего ему индексного файла. В качестве примера рассматривается БД, описываемая отношением:
СТУДЕНТ (ФАМИЛИЯ, ГРУППА, ОЦЕНКИ_СЕССИИ).
и сохраняемая на диске в файле с именем stud.dba. Ей соответствует индексный файл stud.ind.
Каждый из трех предикатов пользовательского интерфейса вызывает свой модуль, выполняющий заданные действия по вводу, добавлению или удалению. Модуль представляет собой набор процедур и правил, которые включают в себя обращение как к стандартным предикатам по работе с файлами, так и к определяемым внутри программы предикатам. Все вновь введенные для каждого из модулей предикаты описываются в секции predicates.
В модуле ввода процедура dbass() присоединяет терм к файлу данных и модифицирует индексный файл, используя обращение к предикатам new_rec() и new_ind(). Первое правило процедуры dbass() предназначено для записи данных в уже существующий файл, т.е. для добавления данных. Второе правило используется для вновь создаваемого файла БД.
Обратим внимание на использование в правиле new_ind() предиката
writef("%7.0\n",Pos).
Этот предикат предназначен для записи значения индекса, задаваемого переменной Pos. Для записи индекса отводится поле, состоящее из семи позиций. Значение, присвоенное переменной Роз, определяет положение записи в файле БД.
В модуле вывода предикат dbrd() возвращает терм из базы данных, обеспечивая его поиск и чтение из файла, а также закрывая файлы после того, как считывание из базы данных выполнено.
В предикате dbrd() используется вспомогательная процедура dbaccess(), которая и служит непосредственно для поиска и выборки нужных данных из файла. Первое правило процедуры используется для чтения данных, логически связанных со значением индекса, задаваемого переменной Pos. Соответствующее значение индекса ищется в индексном файле вторым правилом этой процедуры. Это правило пытается найти в базе такую запись, индекс которой присутствует в индексном файле. Если индекс находится, то правило заканчивается успехом, если не находится - то правило заканчивается неудачей. В случае успеха переменная Term получает нужные пользователю значения.
В модуле удаления предикат dbdel() производит операцию удаления после открытия файла БД и индексного файла, обеспечивая исключение терма из базы. Терм удаляется посредством записи отрицательного числа в индексный файл. Этот модуль использует вспомогательную процедуру dbdel1(), которая осуществляет поиск нужной записи и ее удаление.
Особое внимание следует обратить на предикат flush(). Этот предикат вызывает запись па диск содержимого внутреннего буфера индексного файла. Таким образом, dbdel1() предотвращает возможность работы с данными, которые уже были удалены до этого.
Процедура dbdel1() по свой структуре близка к процедуре dbaccess(). В ней второе правило также предназначено для поиска нужного индекса в индексном файле.
/* Программа по созданию, ведению и доступу к файловой БД stud.dba */
- domains
- name = symbol grup.mark = integer session == mark*
file= dbf; ind
- database
- stud(name, grup, session)
- predicates
- use( string.string) dbassert(dbasedom)
dbass(dbasedom,strmg,string). new_rec(dbasedom ,real) new_ind(real)
dbdelete(dbasedom)
dbdel(dbasedom,string,string)
dbdel l(dbasedom,real) dbread(dbasedom)
dbrd(dbasedom,string,string) dbaccess(dbasedom,real)
- clauses
- use("stud.ind","stud.dba").
/*--- предикаты пользовательского интерфейса СУБД -----*/
dbassert(Term) :- use(Ind,Db), dbass(Term,Ind,Db).
dbdelete(Term) :- use(Ind,Db), dbdel(Term,Ind,Db).
dbread(Term) :- use(Ind,Db), dbrd (Term,Ind,Db).
/*-- модуль ввода данных (терма) в файл базы данных -----*/
dbass(Term,Ind,Db):- existfile(Ind), existfile(Db), openappend(dbf.Db), new_rec(Term,Pos).
openappend(ind,Ind), new_md(Pos).
dbass(Term,Ind.Db):- openwrite(dbf,Db), new_rec(Term,Pos), openwrite(indJnd), new_ind(Pos).
new_rec(Term,Pos):- writedevice(dbf), filepos(dbf\Pos,0), write(Term), closefiie(dbf).
new_ind(Pos):- writedevice(ind), writef("%7.0\n",Pos), closefile(ind).
/*-- модуль вывода данных (терма) из файла базы данных ---*/
dbrd(Tcrm,Ind,Db) :- openread(dbf,Db), openread(ind,Ind), dbaccess(Term,-l).
dbrd(_, _, _) :- closefile(dbf), closefile(ind), fail.
dbaccess(Term,Pos):- Pos>=0, filepos(dbf,Pos,0), readdevice(dbf), readterm(dbasedom,Term).
dbaccess(Term,_):- readdevice(ind), readreal(Pos), dbaccess(Term,Pos).
/*-- модуль удаления данных из БД (запись -1 в индексный файл) -*/
dbdcl(Term,Ind,Db) :- openrcad(dbf,Db), openmodify(ind,Ind), dbdel1(Term,-1).
dbdel(_,_,_) :- closefile(dbf), closefile(ind), fail.
dbdel1(Term,Pos) :- Pos>=0, filepos(dbf,Pos.0), readdevice(dbf), readterm(dbasedom,Term), filepos(md,9,1), flush(ind), writedevice(ind), writef("%7.0\n",-1),flush(ind), writedevice(screen).
dbdel1(Term,_) :- readdevice(ind), readreal(Pos), dbdel1(Term,Pos).