Реалізація високоуровнего інтерфейсу навколо бази даних Berclee DB

[ виправити ] текст може містити помилки, будь ласка перевіряйте перш ніж використовувати.

скачати

МІНІСТЕРСТВО ОСВІТИ І НАУКИ УКРАЇНИ
ОДЕСЬКИЙ НАЦІОНАЛЬНИЙ УНІВЕРСИТЕТ
ім. І. І. Мечникова
ІНСТИТУТ МАТЕМАТИКИ, ЕКОНОМІКИ І МЕХАНІКИ
курсова робота
На тему
«Реалізація високоуровнего інтерфейсу для роботи з базою даних Berkeley DB »
студента 5 курсу
кафедри математичного
забезпечення комп'ютерних систем
Трофімова Бориса
Науковий керівник:
доц. Каменєва А. В.
Одеса 2004

Зміст
1. Введення
2. Основні відомості з баз даних
· Основні визначення та класифікація
· Типи користувачів до БД
· Механізм транзакцій і курсорів
3. Основні відомості з Berkeley DB
4. Основні відомості з програмної системі генерації мов програмування YAPP
5. Структура програми, що розробляється
· Ядро, що включає в себе бібліотеку класів і всі необхідні для роботи стаб інструменти
· Лексичний аналізатор, його структура
· Синтаксичний аналізатор, його структура
· Семантика, генерація С + + стаб (автоматично згенерований програмний код)
6. Приклад роботи програми
7. Висновок
8. Список використаної літератури
9. Програми

1.Вступ
У сучасному інформаційному світі, мабуть, немає місця, де б не використовувалися інформаційні сховища даних - бази даних. Вони потрібні у всіх галузях інформаційного господарства, в них зберігається інформація про курси валют, бронювання авіаквитків, координати супутника і т. д. Природно, доступ до таких даних може здійснюватися в режимі реального часу, отже час, швидкість реакції програмної системи - це один з найістотніших критеріїв.
На сьогоднішній день в результаті природної еволюції частіше використовуються реляційні, мережеві, об'єктно-орієнтовані, а також об'єктно-реляційні бази даних. Найбільшого поширення отримала реляційна модель. Цьому сприяло кілька причин:
1. Реляційна модель є універсальною, тобто з її допомогою в принципі можна реалізувати будь-яку схему даних.
2. Реляційна модель має під собою математичний апарат реляційної алгебри, вона більш формалізована, ніж інші моделі.
3. Реляційна модель має універсальна мова доступу до даних SQL, за допомогою якого можна конструювати запити вже після створення бази даних, і структура яких обмежена тільки лише фантазією користувача (до речі, необов'язково програміста).
Проте за універсальність потрібно платити. І одним зі слабких місць у реляційних СУБД є швидкість виконання запиту! Звичайно, створюються інтелектуальні препроцесора, оптимізують запит, а також час його виконання (так, наприклад, такий є в InterBase, Oracle, Informix), але проблема полягає в самій моделі. Були проведені експерименти, в ході яких робота з навігаційно-мережевий СУБД (Berkeley DB) була ефективніше на порядок, ніж з реляційною СУБД (Informix).
Таким чином, мережні СУБД працюють швидше, однак вони більш заплутаніше, їх семантика більш складна, ніж реляційна, практично недоступна для розуміння кінцевого користувача. Інтерфейс до такої бази даних зазвичай є низькорівневим. Виникає питання, а чи не можна як-небудь підняти рівень абстракції, зробити інтерфейс до неї більш зрозумілим і простим для програміста. Це послужило основою для даної роботи.
Отже, постановка задачі:
Сформувати транслятор генерації об'єктно-орієнтованого інтерфейсу на С + + для роботи з низькорівневої СУБД BerkeleyDB по заданій користувачем схемі даних.

2.Основні відомості з баз даних
База даних - це пойменована сукупність структурованих даних, які стосуються певної предметної області.
У сучасній технології баз даних передбачається, що їх створення, підтримка й забезпечення доступу користувачів здійснюються централізовано за допомогою спеціального програмного інструментарію - систем управління базами даних.
Система управління базами даних (СКБД) - це комплекс програмних і мовних засобів, необхідних для створення баз даних, їх підтримання в актуальному стані та організації в них пошуку необхідної інформації. Іншими словами, СУБД надає інтерфейси для доступу до даних, їх модифікації, а також зберігання.
До основних функцій СУБД прийнято відносити наступні:
· Управління даними у зовнішній пам'яті;
· Управління буферами оперативної пам'яті;
· Управління транзакціями;
· Журналізація і відновлення БД після збоїв;
· Підтримка мов БД;
Будь-яка СУБД забезпечує як мінімум дві послуги.
Перша послуга є доступом до даних. Вона означає, що користувач повинен мати можливість додавати, видаляти, модифікувати дані. Всі сучасні СУБД забезпечують ці послуги.
Друга послуга є управлінням даних. Управління Даних більш складне, ніж доступ до даних. Наприклад, послуги управління даними включають можливість паралелізму. Паралелізм означає, що численні користувачі можуть працювати з БД в один і той же час.
Бази даних про доступ до даних можна розділити на наступні категорії:
· Бази даних з низькорівневим інтерфейсом, такі бази не мають вбудованих засобів визначення типів даних і працюють з «сирими» блоками даних. Вони мають зазвичай досить швидким доступом до даних.
· Бази з високоабстрактним інтерфейсом доступу до даних. У комплект такого інтерфейсу входять засоби визначення даних користувача, а також доступу до них. Такими базами є всі реляційні, об'єктно-орієнтовані, дедуктивні.
Відповідно інтерфейси до них також мають поділ, головним чином в залежності від типу БД. Для нас найбільш важливим буде об'єктно-орієнтований інтерфейс роботи з даними (не обов'язково об'єктами). Такий інтерфейс передбачає тільки об'єктно-орієнтовану роботу з даними, але не роботу з об'єктно-орієнтованими даними. Його побудова і використання обумовлюється найчастіше незручністю роботи з низькорівневими БД.
Користувачі системи баз даних
Тут під користувачем СУБД будемо розуміти суб'єкт (користувач, програміст, прикладна програма), який взаємодіє з яким-небудь інтерфейсом до неї. Користувачів можна розбити на кілька категорій:
Перша - системні, що відповідають за програмування, наприклад оболонок для бази. У нас це суб'єкт, який формує стаб за заданою схемою зберігання даних.
Друга - прикладні, що відповідають за написання прикладних програм, що використовують базу даних (цю оболонку).
Третя - кінцеві користувачі, які працюють з базою даних безпосередньо через інтерфейс-додаток. Він на відміну від перших двох категорій працює не схемою зберігання даних, а безпосередньо з самими даними: додає, видаляє або модифікує їх за потребою.
Механізм транзакцій і курсорів
Транзакція - це послідовність операцій над БД, розглянутих СУБД як єдине ціле. Або транзакція успішно виконується, і СУБД фіксує (COMMIT) зміни БД, вироблені цією транзакцією, у зовнішній пам'яті, або ні одне з цих змін ніяк не відбивається на стані БД, тобто відбувається її відкат. Підтримання механізму транзакцій необхідно для підтримки логічної цілісності БД при роботі одночасно з декількома користувачами, тобто в розрахованих на багато СУБД.
Отже, транзакція має такі властивості:
· Атомарність - або транзакція приймається цілком, або взагалі немає.
· Узгодженість - транзакція починає виконуватися при цілій БД і переводить БД, у разі успішного завершення, також в цілісне стан
· Ізольованість - виконання однієї транзакції не впливає на виконання іншої.
· Стійкість - виконання транзакції не повинно привести до краху БД
Те властивість, що кожна транзакція починається при цілісному стані БД і залишає цей стан цілісним після свого завершення, робить дуже зручним використання поняття транзакції як одиниці активності користувача по відношенню до БД. При відповідному управлінні паралельно виконуються транзакціями з боку СУБД кожен з користувачів може в принципі відчувати себе єдиним користувачем СУБД (насправді, це дещо ідеалізоване уявлення, оскільки в деяких випадках користувачі багатокористувацьких СУБД можуть відчути присутність своїх колег).
З управлінням транзакціями в багатокористувацької СУБД пов'язані важливі поняття серіалізациі транзакцій і серіального плану виконання суміші транзакцій. Під серіалізациі паралельно виконуються транзакцій розуміється такий порядок планування їх роботи, при якому сумарний ефект суміші транзакцій еквівалентний ефекту їх деякого послідовного виконання. Серіальний план виконання суміші транзакцій - це такий план, який призводить до серіалізациі транзакцій. Зрозуміло, що якщо вдається домогтися дійсно серіального виконання суміші транзакцій, то для кожного користувача, з ініціативи якого утворена транзакція, присутність інших транзакцій буде непомітно (якщо не вважати деякого уповільнення роботи в порівнянні з одного користувача режимі).
Існує кілька базових алгоритмів серіалізациі транзакцій. У централізованих СУБД найбільш поширені алгоритми, засновані на синхронізаційних захопленнях об'єктів БД. При використанні будь-якого алгоритму серіалізациі можливі ситуації конфліктів між двома або більше транзакціями з доступу до об'єктів БД. У цьому випадку для підтримки серіалізациі необхідно виконати відкат (ліквідувати всі зміни, зроблені в БД) однієї або більше транзакцій. Це один із випадків, коли користувач багатокористувацької СУБД може реально (і досить неприємно) відчути присутність в системі транзакцій інших користувачів.
При дотриманні обов'язкової вимоги підтримки цілісності бази даних можливі такі рівні ізольованості транзакцій:
· Перший рівень - відсутність втрачених змін. Розглянемо наступний сценарій спільного виконання двох транзакцій. Транзакція 1 змінює об'єкт бази даних A. До завершення транзакції 1 транзакція 2 також змінює об'єкт A. Транзакція 2 завершується оператором ROLLBACK (наприклад, через порушення обмежень цілісності). Тоді при повторному читанні об'єкта A транзакція 1 не бачить змін цього об'єкта, проведених раніше. Така ситуація називається ситуацією втрачених змін. Природно, вона суперечить вимозі ізольованості користувачів. Щоб уникнути такої ситуації в транзакції 1 потрібно, щоб до завершення транзакції 1 ніяка інша транзакція не могла змінювати об'єкт A. Відсутність втрачених змін є мінімальною вимогою до СУБД по частині синхронізації паралельно виконуваних транзакцій.
· Другий рівень - відсутність читання "брудних даних". Розглянемо наступний сценарій спільного виконання транзакцій 1 і 2. Транзакція 1 змінює об'єкт бази даних A. Паралельно з цим транзакція 2 читає об'єкт A. Оскільки операція зміни ще не завершена, транзакція 2 бачить неузгоджені "брудні" дані (зокрема, операція транзакції 1 може бути відвернута при перевірці негайно перевіряється обмеження цілісності). Це теж не відповідає вимозі ізольованості користувачів (кожен користувач починає свою транзакцію при узгодженому стані бази даних і в праві чекати бачити узгоджені дані). Щоб уникнути ситуації читання "брудних" даних, до завершення транзакції 1, змінила об'єкт A, ніяка інша транзакція не повинна читати об'єкт A (мінімальною вимогою є блокування читання об'єкта A до завершення операції його зміни в транзакції 1).
· Третій рівень - відсутність неповторюваних читань. Розглянемо такий сценарій. Транзакція 1 читає об'єкт бази даних A. До завершення транзакції 1 транзакція 2 змінює об'єкт A і успішно завершується оператором COMMIT. Транзакція 1 повторно читає об'єкт A і бачить його змінений стан. Щоб уникнути неповторюваних читань, до завершення транзакції 1 ніяка інша транзакція не повинна змінювати об'єкт A. У більшості систем це є максимальним вимогою до синхронізації транзакцій, хоча, як ми побачимо трохи пізніше, відсутність неповторюваних читань ще не гарантує реального ізольованості користувачів.
Зауважимо, що існує можливість забезпечення різних рівнів ізольованості для різних транзакцій, що виконуються в одній системі баз даних (зокрема, відповідні оператори передбачені в стандарті SQL 2). Як ми вже відзначали, для підтримки цілісності достатній перший рівень. Існує ряд програм, для яких першого рівня достатньо (наприклад, прикладні або системні статистичні утиліти, для яких некоректність індивідуальних даних неістотна). При цьому вдається істотно скоротити накладні витрати СУБД і підвищити загальну ефективність.
Курсори є абсолютно іншою сутність БД. Однією з найпоширеніших операцій з БД є надання набору інформації по запиту користувача. У реляційній БД це організується через конструкцію "select ...". Отже, результатом виконання такого запиту буде набір даних, взятий з БД. Однак як отримати доступ до цих даних? Відповідно до нової парадигмою ООП - шаблонами проектування, визначається певний об'єкт, званий курсором, який виконує функції простого ітератора. Фактично через його інтерфейс користувач у стані перебирати всі дані, що зберігаються в отриманому наборів довільному порядку.
Такий об'єкт має зазвичай такий інтерфейс:
Init (...); створення ітератора
Bool GetNextInfo (); перейти на наступну порцію даних
GetCurrData (); отримати поточну порцію даних
Ще однією особливістю ітератора є те, що крім перебору даних, він завжди вказує на якусь одну порцію даних.
Природно, поняття курсору тісно пов'язане з механізмом транзакцій.
Дійсно, з моменту виконання запиту щодо надання курсору клієнту база ні як не блокується і доступна для операцій інших клієнтів. Використання транзакцій дозволило б у випадку конфлікту повернути базу в несуперечливе стан. Тому всі дії з курсором повинні бути обгорнуті в транзакційні дужки.
3.Основні відомості з BerkeleyDB
Berkeley DB - «open source» бібліотека баз даних, яка забезпечує масштабується, швидкодіюче, управління даних, їх захист в додатку. Berkeley DB забезпечує простій функціональний виклик API для доступу до даних та їх управління для безлічі мов програмування, включаючи C, C + +, Java, Perl, Tcl, Pyton, і PHP. Всі операції з базою відбуваються в бібліотеці. Низький рівень операцій включає в себе механізм блокувань, транзакційних блокувань, колективного буферного управління, управління пам'яті і т. п.
За класифікацією BerkeleyDB є навігаційно-мережною базою з можливістю переміщення по покажчиках структур. Однак ці покажчики вказівники на оперативну пам'ять а не на жорсткий диск, що кілька відрізняє її від мережевих.
Бібліотека є досить портативної. Вона працює під майже всіма UNIX і варіантами Linux, Windows, і безліччю інших операційних систем у реальному часі. Вона працює як на 32 - бите так і 64-бітових системах.
Сама база даних бібліотеки є надзвичайно компактною (під 300 кілобайтами текстового простору в загальній архітектурі), але вона може керувати базами даних аж до 256 terabytes. Вона також підтримує високий паралелізм, з тисячами користувачів, що діють на тій же базі даних в той же самий час.
Програми Berkeley DB містять достатню кількість схем зберігання даних, які найкращим чином підходять додатком. Berkeley DB підтримує таблиці типу Hash, Btrees, прості черзі з числовим доступом до даних і стійкі черги. Програмісти можуть створити таблиці, що використовують будь-яку з цих структур пам'яті, і можуть змішати операції в інших типах таблиць у своєму додатку.
Таблиці Hash зазвичай хороші для дуже великих баз даних, коли необхідний пошук і розумний час корекції для довільного доступу записів. Таблиці Hash дозволяють питати, "цей об'єкт існує?" або, щоб вибирати запис з відомим об'єктом. Таблиці Hash не дозволяють, наприклад, вимагати записи з об'єктами, які близькі до відомого об'єкта. Btree використовується для пошуків, які базуються на діапазонах, коли додатку потрібно знаходити всі записи з об'єктами між деяким початковим значенням і кінцем. Btree також підходить для організації посилальної залежності. Структура Btree зберігає близькі дані поряд у пам'яті (на диску), так що при виборі сусідніх величин звичайно не потрібно дисковий доступ. Черги, засновані на числовій індексації записів. Кожен запис має унікальний номер. І пошук, видалення, зміна запису здійснюється через цей номер. Berkeley DB генерує ці рекордні номери автоматично.
Berkeley DB підтримує найважливіші послуги управління даними, включаючи паралелізм, транзакційних та відновлення, сторінкове керування кешем. Всі вони працюють для будь-яких варіантів зберігання даних.
Berkeley DB не є сервером баз даних. Так як бібліотека для роботи з Berkeley завантажується в адресний простір програми і доступно тільки для нього. Хоча таке рішення реалізовується.
Отже, Berkeley DB складається з наступних об'єктів: Dbt, Db, DbEnv. Вони пов'язані наступним чином
Dbt
Db
таблиця
DbEnv - база даних


4.Основние відомості з програмної системі генерації мов програмування YAPP

YAPP являє собою програмну систему з використанням Perl для генерації та використання синтаксичних аналізаторів LALR. Фактично це колекція модулів розширення, написаних на Perl, сумісна з форматом YACC і дозволяють генерувати perl-код.

Користувач формує файл з граматикою, яка описує деякий потрібну мову. Цей файл подається на вхід до yapp
yapp grammar_file.yp
На виході отримуємо perl-модуль, що виконує синтаксичний аналізатор мови, описуваного користувачем. Тобто, фактично, yapp і генерує синтаксичні аналізатори.
Щоб підключити синтаксичний аналізатор, користувач повинен підготувати вже своїми силами лексичний аналізатор і використовувати приблизно такий код:
use MyParser;
$ Parser = new MyParser ();
$ Value = $ parser-> YYParse (yylex => \ & lexer_sub, yyerror => \ & error_sub);
Файл граматики
1) Комментарии бывают в стиле Perl # или в стиле С // , /* */.
2) Признаки литералов и строк.
У будь-якому граматичному файлі можуть з'явитися тільки два типи символів: нетермінальні символи, які назвали також ліво-лежать символи (імена правил), і термінальні символи названі також лексемами. Лексеми є символами, що отримуються на виході лексичного аналізатора.
Синтаксис нетермінальних символів і символьних лексем:
[A-Za-z] [A-Za-z0-9_] *.
Заборонено використання назву «error» для літералів.
Структура его выглядит следующим образом (очень похожа на yacc , фактически является ее подмножеством)
Файл состоит из трех секций, разделенных %% :
заголовок
%%
секція правил
%%
нижня секція
Заголовна секція містить будь-яка коректна код Perl, який копіюється дослівно в самий початок майбутнього модуля синтаксичного аналізатора. Це корисна річ, наприклад для оголошення глобальних змінних.
Вона містить також декларації пріоритету, представлених   % left , % right і % nonassoc (определяющ. ассоциативность).
% start указывает на правило(левую часть), выполняющееся первым.
Секція правил містить граматичні правила:
Кожне правило складається з ліворуч лежачого символу (нетермінального), розділеного ':' и одним или несколькими возможными правилами, разделенными '|' и завершенными ';':
exp: exp '+' exp
| Exp '-' exp
;
Правило справа може бути порожнім
input: # empty
| Input line
;
Для завдання явного пріоритету у разі неоднозначності слід використовувати директиву % divc , дающую правилу высокий приоритет.
exp: '-' exp% divc NEG {- $ _ [1]}
| Exp '+' exp {$ _ [1] + $ _ [3]}
| NUM
;
Примітно, що YAPP дозволяє вбудовувати в синтаксичний аналізатор семантику. Це організується шляхом додавання в кінці правила конструкцій {...}, що обмежують Perl-команди. Вони вбудовуються в синтаксичний аналізатор і виконуються після застосування аналізатором цього правила. Такий код може повертати деяку величину, використовувану у визначенні наступного правила по дереву.
Змінні $ _ [1], $ _ [n] є параметрами і зберігають значення розібраного правила.
Нижняя секция может содержать корректный Perl -код, встраиваемый в конце сформированного синтаксического анализатора. Там можно указать лексер, процедуру анализа ошибок. -код, встраиваемый в конце сформированного синтаксического анализатора. Там можно указать лексер, процедуру анализа ошибок.
5.Структура розроблюваної програми
Ідеологія оболонки полягає в тому, що користувач майбутньої бази даних спочатку описує на спеціальній мові структури даних, з яких повинні складатися таблиці в базі (тобто фактично інтерфейси) їх посилальні зв'язку, індекси тощо Потім за допомогою спеціального транслятора він отримує готовий С + + код, що реалізовує інтерфейс роботи з базою даних, визначений користувачем, включаючи саму базу, її таблиці, запису даних, транзакції і деякі інші об'єкти. Код, що генерується транслятором, насправді, є теж оболонкою. Справа в тому, що багато частин транслятора мають під собою загальне підставу. Ці статичні класи та функції можна виділити в бібліотеку. Ще одна причина для цього - семантика самого транслятора повинна бути як можна простіше. І як наслідок цього, скорочуються розміри генеруються файлів.
Отриманий програмний код залишається тільки включити в проект і використовувати вже готові об'єкти бази даних і таблиць.
Нова база даних повинна мати такі можливості:
· Додавання користувача даних їх модифікація і видалення.
· Відкриття бази в декількох режимах: наприклад, в нормальному многопользовательском транзакційному режимі, безпечному режимі (як правило, для монопольного доступу і використовується утилітами), а також у режимі відновлення бази даних.
· Імпорту даних, тобто, представлення даних в деякому текстовому форматі, і їх переміщення в пусту базу даних
· Експорту даних, тобто, переміщення даних з бази, і подання їх у певному текстовому форматі у файлі, зручному для читання. Є взаємно зворотною операцією попередньої.
· Перевірки індексного цілісності. Справа в тому, що іноді, внаслідок різних зовнішніх факторів (наприклад, перепад напруги), втрачається актуальність і коректність даних в індексних таблицях, і їх необхідно періодично перевіряти і в разі необхідності відновлювати.
· Перевірки посилальної цілісності. Тобто перевірка коректності логічних залежностей між таблицями в базі.
Отже, вся оболонка складається з наступних частин:
1. Власне, базова бібліотека статичних класів, для високорівневої роботи з Berkeley, необхідна транслятору.
2. Транслятор, який, також є генерується оболонкою під типи даних користувача навколо бібліотеки.
Бібліотека класів
«Движок» являє собою бібліотеку класів, які з одного боку є надбудовами навколо стандартних відповідних структур, а з іншого боку роблять їх інтерфейс більш зручним і інкапсулюють частину роботи транслятора. Основними компонентами є:
· Транзакції
· Винятки
· Базові запису
· Таблиці
· Бази даних
· Курсори
Базові запису
Базова запис - це елементарна одиниця зберігання в таблиці. Опис її класу:
/ /! базовий клас для записів з vtable pointer
class hbObj {
Dbt dbt;
protected:
void dbtInit (uint s, void * d)
{
dbt.set_flags (DB_DBT_USERMEM);
dbt.set_ulen (s);
dbt.set_size (s);
dbt.set_data (d);
}
public:
operator Dbt * () {return &dbt;}
void * getData (void) {return dbt.get_data ();};
uint getSize (void) {return dbt.get_size ();};
hbObj () {}
virtual ~ hbObj () {}
};
Цей клас не зовсім зручний для безпосереднього використання. Справа в тому, що він нічого не знає про вихідні дані, які буде в собі утримувати. Цими даними можуть бути, наприклад, розмір структури в пам'яті і деякі її методи. Найпростішим рішенням буде введення шаблона з передачею типу збереженої структури як його параметра.
/ /! реальний клас, який приводиться до Dbt
template <class A> class hbRec: public hbObj
{
A data;
public:
A * getPnt (void) {return &data;} / / якщо в у A масив то можна перевизначити операцію & для А
hbRec () {memset (& data, 0, sizeof (A)); dbtInit (sizeof (A), & data);}
hbRec (const hbRec <A> & a): data (a.data) {dbtInit (sizeof (A), & data);}
hbRec (const A & a): data (a) {dbtInit (sizeof (A), & data);}
void SetData (const A & a) {data = a; dbtInit (sizeof (A), & data);}
virtual ~ hbRec () {}
};
Таблиці
Діаграма відносин існуючих таблиць наведена нижче:
SHAPE \ * MERGEFORMAT
State-Queue
hbBasetbl
State-BTree
State-Hash
hbPTable
Final templated class hbTable <record type>

За аналогією з записами існує базовий клас таблиць hbBasetbl, який підтримує роботу з усіма стандартними типами таблиць (Hash, Btree, Queue). Фактично її тип є її станом і визначається в момент відкриття.
class hbBasetbl
{
/ / Потрібен для того щоб set_flags викликалася рівно один раз
        uint Set_flg_Counter;
ushort state;
/ / Прапор, показивающе. відкрита чи сама таблиця, необхідний для екстрим. закриття у разі некоректні
         / / Відкриття
bool tableopen;
hbInit ini;
protected:
uint recsize;
uint keysize; / / тільки для DB_HASH
Db * table;
virtual void UsrOpen (hbTxn * tx, FileConf & conf, bool openidx, hbInitRt * irt = 0, u_int32_t op_flags = 0);
virtual void UsrClose ();
void SetRecSize (uint recsize1) {recsize = recsize1;}
void SetKeySize (uint keysize1) {keysize = keysize1;}
uint GetType () {return ini.type;}
bool IsDup () {return (ini.st_flags & DB_DUP | ini.st_flags & DB_DUPSORT)> 0;}
public:
hbEnv & env;
operator Db * () {return table;}
Db * operator ->(){ return table;}
const char * GetDbName () {return ini.dbname;}
hbBasetbl (hbEnv & e, hbInit &);
virtual ~ hbBasetbl () {if (state) Close ();}
void Open (hbTxn * tx, FileConf & conf, bool openidx, hbInitRt * irt = 0, u_int32_t op_flags = 0);
void Close ();

virtual void Create (hbTxn * tx, FileConf & conf, hbInitRt * irt = 0, u_int32_t op_flags = 0);
virtual int Get (hbTxn * tx, hbObj * key, hbObj * val, u_int32_t flags = 0); / / у стилі С (без виключень)
virtual int Pget (hbTxn * tx, hbObj * fkey, hbObj * pkey, / / ​​в стилі С (без виключень)
hbObj * val, u_int32_t flags = 0);
virtual int Del (hbTxn * tx, hbObj * key, u_int32_t flags = 0); / / у стилі С (без виключень)
virtual int tGet (hbTxn * tx, hbObj * key, hbObj * val, u_int32_t flags = 0); / / у стилі С + +
virtual int tPget (hbTxn * tx, hbObj * fkey, hbObj * pkey, hbObj * val, u_int32_t flags = 0); / / у стилі С + +
virtual int tDel (hbTxn * tx, hbObj * key, u_int32_t flags = 0); / / у стилі С + +
virtual int Put (hbTxn * tx, hbObj * key, hbObj * val, u_int32_t flags = 0);
bool IsOpen () {return state;}
};
Для прискорення доступу за якимось критерієм до даних в таблицях вводяться індексні таблиці. Ними можуть бути будь-які з перерахованих, звичайно відповідно до їх особливостями. Клас hbBasetbl є з одного боку базовим класом, що містить всю рутинну роботу з прапорами і основними операціями з таблицею, а з іншого боку-фінальним класом для індексного таблиці.
Цей клас є базовим, і зовсім незручний для роботи, якщо ця таблиця є індексованої (тобто має індекси - інші індексні таблиці). Необхідний ще один клас, який буде узагальненням поняття индексируемой таблиці і бути контейнером для таких індексних таблиць. Цей клас представлений нижче.
class hbPTable: public hbBasetbl {
void ErrorClose ();
void eee ();
void FixIdx (uint bulk_ret_buffer_size, int i, FileConf & conf);
void FixIdxForQueue (uint bulk_ret_buffer_size, int i, FileConf & conf);
void FixIdxForHash (uint bulk_ret_buffer_size, int i, FileConf & conf);
void CheckMainToIdx (uint bulk_ret_buffer_size, bool fix, FileConf & conf);
void CheckMainToIdxForQueue (uint bulk_ret_buffer_size, bool fix, FileConf & conf);
void CheckMainToIdxForHash (uint bulk_ret_buffer_size, bool fix, FileConf & conf);
void CheckIdxToMain (uint bulk_ret_buffer_size, bool fix, FileConf & conf);
void CheckIdxToMainForQueue (uint bulk_ret_buffer_size, bool fix, FileConf & conf);
void CheckIdxToMainForHash (uint bulk_ret_buffer_size, bool fix, FileConf & conf);
inline void ExportForQueue (uint bulk_ret_buffer_size, FILE * f, hbTxn * tx);
inline void ExportForHash (uint bulk_ret_buffer_size, FILE * f, hbTxn * tx);
inline void Import3 (Dbt * key, Dbt * data);
inline void Import2 (char * buf);
inline void Import1 (FILE * f, char * & buf1, uint &);
inline void CheckForRefForQueue (uint bulk_ret_buffer_size);
inline void CheckForRefForHash (uint bulk_ret_buffer_size);
inline uint GetMaxRefRecBuf ();
protected:
int sz;
IdxItem * idx;
RefItems ref;
virtual void UsrOpen (hbTxn * tx, FileConf & conf, bool openidx, hbInitRt * irt = 0, u_int32_t flags = 0);
virtual void UsrClose ();
inline virtual void ExportDBTemplate (FILE *, const char *, const char *) = 0;
inline virtual void ImportDBTemplate (char * buf1,
uint buf1len,
char * buf2,
uint buf2len,
hbObj * & Key,
hbObj * & Val) = 0;
public:
/ /! конструктор приймає масив ініціалізаторов (в тч індексів)
hbPTable (hbEnv & env, hbInit & ini1);
virtual ~ hbPTable ();
/ / Перевірка індексного цілісності
void CheckIdx (uint bulk_ret_buffer_size, bool fix);
/ / Перевірка посилальної цілісності
void CheckForRef (uint bulk_ret_buffer_size);
void Export (uint bulk_ret_buffer_size, FILE * f, hbTxn * tx);
void Import (FILE * f, char * & buf, uint &);
virtual int Pget (hbTxn * tx, int n, hbObj * fkey, hbObj * pkey, hbObj * val, u_int32_t flags = 0)
{Return idx [n]. Table.Pget (tx, fkey, pkey, val, flags);}
hbBasetbl & GetIdx (int n)
{Return idx [n]. Table;}
inline uint GetIdxCount () {return sz;}
inline uint GetRecSize () {return recsize;}
};
Як бачимо, цей клас розширює старий інтерфейс шляхом введення утилітарних методів експорту, імпорту, різного роду перевірок та операціями з індексними таблицями. Однак цього класу також не зручний у роботі, так як не знає нічого про типи структур і її характеристики. Введення цих типів як параметрів шаблону дозволило б дуже спростити роботу з інтерфейсом индексируемой таблиці (але не розширити!). Результат наведено нижче:
template <class Key,class Val> class hbTable: public hbPTable
{
public:
/ /! конструктор приймає масив ініціалізаторов (в тч індексів)
hbTable (hbEnv & e, hbInit & ini1): hbPTable (e, ini1) {SetRecSize (sizeof (Val)); SetKeySize (sizeof (Key));}
/ / SetRecSize use by QUEUE only
virtual ~ hbTable () {}
/ / Більш просунуті функції
int Get (const bexcp & excp, hbTxn * tx, const Key & key, Val * val, u_int32_t flags = 0)
{
Get (excp, tx, (Key *) & key, val, flags);
}
int Pget (const bexcp & excp, hbTxn * tx, int n, hbObj * fkey, Key * pkey, Val * val, u_int32_t flags = 0)
{
MTRY
hbRec <Key> k;
hbRec <Val> v;
int z = Pget (tx, n, fkey, & k, & v, flags);
* Pkey = * (k.getPnt ());
* Val = * (v.getPnt ());
return z;
CATCH_hbExcp
}
int Del (const bexcp & excp, hbTxn * tx, const Key & key, u_int32_t flags = 0)
{
Del (excp, tx, (Key *) & key, flags);
}
int tGet (const bexcp & excp, hbTxn * tx, Key * key, Val * val, u_int32_t flags = 0)
{
MTRY
hbRec <Key> k (* key);
hbRec <Val> v;
int z = tGet (tx, & k, & v, flags);
* Val = * (v.getPnt ());
return z;
CATCH_hbExcp
}
int Put (const bexcp & excp, hbTxn * tx, const Key & key, const Val & val, u_int32_t flags = 0)
{
Put (excp, tx, (Key *) & key, (Val *) & val, flags);
}
uint Append (const bexcp & excp, hbTxn * tx, Val * val)
{
MTRY
if (GetType ()! = DB_QUEUE) return 0;
hbRec <uint> k;
hbRec <Val> v (* val);
hbBasetbl:: Put (tx, & k, & v, DB_APPEND);
return (uint &) * (k.getPnt ());
CATCH_hbExcp
}
uint Append (const bexcp & excp, hbTxn * tx, const Val & val)
{
return Append (excp, tx, (Val *) & val);
}
};
Цей параметризованих клас насправді тільки перевизначив сигнатури методів більш зручними і працюючими з користувача типами даних.
База даних або об'єкт оточення
Цей об'єкт фактично являє собою абстракцію бази даних: є контейнером для індексованих таблиць, відповідає за це відкриття, доступ, а також проводить над ними службові операції експорту і т.п. На діаграмі це виглядає так:
SHAPE \ * MERGEFORMAT
hbEnv
hbPTable
indexed table
hbDict
hbBaseTbl
index table

Опис класу наведено нижче:
class hbEnv
{
DbEnv * env;
bool is_native_log;
Log * LogObj;
        / /! Шлях до файлів
char * path;
/ /! Кількість баз - ламає вектором писати - тоді довше Компілім
int sz;
/ /! Інішіалайзери (у кількості, що дорівнює sz)
hbInit * dbinits;
hbInit * idxinits;
int idxsz;
char * schemaid; / / вже перевіряється, при відкритті зі словника чит. оригіна. і порівнюється
/ /! Мутекс для транзакцій
pthread_mutex_t mx;
       uint dltype;
/ /! in secs interval for checkpoints and logarchs
ulong dldelay, bdbchkpoint, bdblogrem;
static void * thf_deadrs (void *);
static void * thf_chkpnt (void *);
static void * thf_logarc (void *);
pthread_t pth_deadrs, pth_chkpnt, pth_logarc;
        ushort stflags;
ushort stflags;
bool IsOpenflag;
ushort state;
        TDictionary dict;
/ / Char * ConfFile; / / ім'я конф. файлу може визначити у нащадках / але навіщо
FILE * OpenOutputStream (const char * fn, const char * mode);
        void CloseOutputStream (FILE * f);
/ / Видаляє всі __db.00x файли т.к там зберігається хеш, через який може невірно спрацювати перевірка індексів
protected:
/ /! Самі тейбл, індексів тут немає, вони в самих тейбл
        hbPTable ** dbs;
void SetSchemaid (const char * File) {if (schemaid) free (schemaid); schemaid = strdup (File);}
        / / Тейбли будуть створюватися в конструкторі нащадка, та бути внесені в dbs
        int Close (int);
virtual void UsrClose ();
public:
Log * GetLog () {return LogObj;}
operator DbEnv * () {return env;};
DbEnv * operator -> () {return env;}
/ / DbEnv & GetDbEnv () {return env;}
const char * GetSchemaId () const {return schemaid;}
const char * GetUuid (const bexcp &, hbTxn * tx);
const char * GetPath () const {return path;}
bool IsOpen () {return state;}
hbEnv (const char * p, envInit & e, ushort flt = LL_DEBUG, Log * LogObj1 = 0);
virtual ~ hbEnv ();
/ / St_flags приміщ. в DbEnv:: set_flags (DB_TXN_NOSYNC)
/ / Op_flags приміщ. в Db:: open (DB_PRIVATE / DB_THREAD - by default)
/ / Якщо режим CDS то ці прапори ігноруються за винятком op_flags = DB_PRIVATE!!
void OpenTDSMode (const bexcp & excp, u_int32_t st_flags = 0, u_int32_t op_flags = (DB_THREAD | DB_RECOVER)) / / DB_THREAD | DB_RECOVER_FATAL
{DBOpen (excp, OPEN_TDS, true, st_flags, op_flags);}
void OpenCDSMode (const bexcp & excp, bool opentables = true, u_int32_t op_flags = 0 / * тільки для DB_PRIVATE * /)
{DBOpen (excp, OPEN_CDS, opentables, 0, op_flags);}
void Close (const bexcp & excp);
void Close ();
/ / Повна ініціалізація & створення бази з нуля (попереднє видалення БД)
void Init (const bexcp & excp, u_int32_t op_flags = DB_THREAD);
/ / Перевірка індексів і коли треба їх коригування база повинна бути в offline
void CheckForIdx (const bexcp & excp, uint bulk_ret_buffer_size = (5 * 1024 * 1024), bool fix = false);
void CheckForRef (const bexcp & excp, uint bulk_ret_buffer_size = (5 * 1024 * 1024));
/ /! експорт бази даних
void ExportDB (const bexcp & excp, const char * fn, uint bulk_ret_buffer_size = (5 * 1024 * 1024));
/ /! імпорт бази даних
void ImportDB (const bexcp & excp, const char * fn);
void printf (ushort level, const char * fmt ,...); / / обгортка під Log:: printf
};
Цей клас інкапсулює роботу зі словником, де може зберігатися інформація, корисна для програміста.
Транзакції
Клас транзакцій має наступний вигляд:
class hbTxn {
hbEnv & Env;
bexcp excp1;
hbTxn * parent;
DbTxn * Txn;
void SetFlags () {}
hbTxn (const hbTxn & Txn1): Env (Txn1.Env) {} / / copy constr
hbTxn & operator = (const hbTxn &) {return * this;} / /: =
public:
operator DbTxn * () {return Txn;};
hbTxn (const bexcp & excp, hbEnv & env1, ullong flags = 0, hbTxn * parent1 = 0); / / молодші 32 біти це / / звичайна. Берклі. прапори 33 біт відповідає за негайне старт транзакції одразу ж після створення
hbTxn (const bexcp & excp, hbTxn * parent1, ullong flags = 0);
/ / --- "---
~ HbTxn ();
bool HaveParentTxn () {return parent! = 0;}
void Start (const bexcp & excp, ulong flags = 0);
void Commit (const bexcp & excp, ulong flags = 0);
void RollBack (const bexcp & excp);
/ / Void RollBack ();
};
Його особливістю є те, що створений об'єкт транзакції не можна копіювати або створювати копіюванням. А також такий об'єкт повинен створюватися автоматично, тобто як стекова мінлива:
try
{
hbTxn tx (excp, parent_tx);
/ / Операції з базою
tx.Commit ();
}
catch (...) {}
Як бачимо, перше - не треба дбати про видалення об'єкта транзакції (при будь-якій ситуації), друге - у разі виключення Rollback () викличеться автоматично в деструктор цього об'єкта.
Транслятор
Як вже говорилося, завдання транслятора полягає в тому, щоб створити за бажанням користувача максимально зручну оболонку для бібліотеки відповідно до його визначеннями основних елементів бази.
Файл граматики наведено нижче:
%%
#------------------------------------------------- ------
#------ COMMENTS --------------------------------------
#------------------------------------------------- ------
# Id ідентифікатор
# String строковий літерал або ідентифікатор
# Num чіловой літерал
# Float літерал числа з плаваючою точкою
# Char символьний літерал
# Rawcode:: = будь-яка последователность коду між '{*' і '*}'
file: 'end' {tblproc:: Finish ();}
| Filetext 'end' {tblproc:: Finish ();}
;
filetext: item
| Item filetext
;
item: optionblock
| Idxblock
| Structblock
| Enumblock
| Codeblock
| Tableblock
;
literal: string {[$_[ 1], 0]}
| Num {[$_[ 1], 1]}
| Float {[$_[ 1], 2]}
| Char {[$_[ 1], 3]}
;
#------------------------------------------------- --------
optionblock: 'option' '{' oplist '}' ';'
{Tblproc:: OptBlockPrint ('',$_[ 3]);}
| 'Option' opitem ';'
{Tblproc:: OptBlockPrint ('',[$_[ 2 ]]);}
| 'Option' id '{' oplist '}' ';'
{Tblproc:: OptBlockPrint ($ _ [2 ],$_[ 4]);}
| 'Option' id opitem ';'
{Tblproc:: OptBlockPrint ($ _ [2 ],[$_[ 3 ]]);}
;
oplist:
opitem ';' {[$_[ 1]]}
| Opitem ';' oplist {push{$_[ 3]}, $ _ [1]; $ _ [3]}
;
opitem: id '=' literal
{[$_[ 1 ],@{$_[ 3]} [0], 0 ,@{$_[ 3]} [1]]}
| Id '=' id {[$_[ 1 ],$_[ 3], 1 ,'']}
;
#------------------------------------------------- --------
idxblock: 'idx' id idxitem ';'
{Tblproc:: IdxBlockPrint ($ _ [2 ],[$_[ 3 ]]);}
| 'Idx' id '{' idxitemlist '}' ';'
{Tblproc:: IdxBlockPrint ($ _ [2 ],$_[ 4]);}
;
idxitemlist: idxitem ';' {[$_[ 1]]}
| Idxitem ';' idxitemlist {unshift{$_[ 3 ]},$_[ 1]; $ _ [3]}
;
idxitem: idxmod1 id '(' flist1 ')'
{[0, $ _ [1 ],$_[ 2 ],$_[ 4 ],'']}
| Idxmod1 id '(' flist1 ')' '{*' rawcode '*}'
{[0, $ _ [1 ],$_[ 2 ],$_[ 4 ],$_[ 7]]}
| Idxmod2 id '(' flist2 ')' {[1, $ _ [1 ],$_[ 2 ],$_[ 4 ],'']}
| Idxmod2 id '(' flist2 ')' '{*' rawcode '*}'
{[1, $ _ [1 ],$_[ 2 ],$_[ 4 ],$_[ 7]]}
;
idxmod1: '.!'
| ':!'
| '%!'
;
idxmod2: '.'
| ':'
| '%'
;
flist1: id {[[$_[ 1 ],'']]}
| Id ',' flist1 {unshift
{$_[ 3 ]},[$_[ 1 ],''];$_[ 3]}
;
flist2: idxmod3 id {[[$_[ 2 ],$_[ 1]]]}
| Idxmod3 id ',' flist2 {unshift
{$_[ 4 ]},[$_[ 2 ],$_[ 1 ]];$_[ 4]}
;
idxmod3: '+'
| '-'
| '^'
;
#------------------------------------------------- --------
codeblock: code 'decl' '{*' rawcode '*}'
{Tblproc:: CodeBlockPrint ('hh', \ $ _ [4], 0);}
| Code 'tab' '{*' rawcode '*}'
{Tblproc:: CodeBlockPrint ('tab', \ $ _ [4], 0);}
| Code 'def' '{*' rawcode '*}'
{Tblproc:: CodeBlockPrint ('cc', \ $ _ [4], 0);}
| Code 'def' 'top' '{*' rawcode '*}'
{Tblproc:: CodeBlockPrint ('cc', \ $ _ [5], 1);}
| Code '{*' rawcode '*}'
{Tblproc:: CodeBlockPrint ('all', \ $ _ [3], 0);}
;
#------------------------------------------------- --------
enumblock: 'enum' id '{' enumlist '}' ';'
{Tblproc:: EnumBlockPrint ($ _ [2 ],$_[ 4]);}
| 'Enum' id ';'
{Tblproc:: EnumBlockPrint ($ _ [2 ],[]);}
;
enumlist: enumitem {[$_[ 1]]}
| Enumitem ',' enumlist {unshift{$_[ 3]}, $ _ [1]; $ _ [3]}
;
enumitem: id {[$_[ 1 ],'']}
| Id '=' num {[$_[ 1 ],$_[ 3]]}
;
#------------------------------------------------- --------
structblock: 'struct' id '{' structlist '}' ';'
{Tblproc:: StructBlockPrint ($ _ [2 ],$_[ 4]);}
;
structlist: structitem {[$_[ 1]]}
| Structitem structlist {unshift{$_[ 2]}, $ _ [1]; $ _ [2]}
;
structitem: id pnlistid ';'
{[$_[ 1 ],@{$_[ 2]} [0 ],@{$_[ 2]} [1]]}
;
#------------------------------------------------- --------
tableblock: tableforward
{Tblproc:: TableBlockPrint (@{$_[ 1]} [0 ],'',[],[]);}
| Tablehead ';'
{Tblproc:: TableBlockPrint (@{$_[ 1]} [0 ],@{$_[ 1]} [1 ],@{$_[ 1]} [2], []);}
| Tablehead tail ';'
{Tblproc:: TableBlockPrint (@{$_[ 1]} [0 ],@{$_[ 1]} [1 ],@{$_[ 1]} [2], $ _ [2]);}
;
tail: idxtailitem {$ _ [1]}
| Idxtailitem tail {unshift{$_[ 2 ]},$_[ 1 ];$_[ 2]}
| Optiontailitem
| Optiontailitem tail
;
tableforward: 'table' id ';' {[$_[ 2]]}
;
tablehead: 'table' memmodifid '{' memberlist '}'
{[@{$_[ 2]} [0 ],@{$_[ 2]} [1 ],$_[ 4]]}
;
memmodifid: id {[$_[ 1 ],'']}
| Memmodificator id {[$_[ 2 ],'$']}
;
memberlist: memberitem {[$_[ 1]]}
| Memberitem memberlist {unshift{$_[ 2]}, $ _ [1]; $ _ [2]}
;
memberitem: id pnlistid ';'
{[$_[ 1 ],@{$_[ 2]} [0 ],@{$_[ 2]} [1 ],[]]}
| Id pnlistid modificator1 ';'
{[$_[ 1 ],@{$_[ 2]} [0 ],@{$_[ 2]} [1 ],$_[ 3]]}
;
modificator1: idxmodificator {[$_[ 1],'']}
# | Idxmodificator memmodificator {[$_[ 1],'$','']}
| Idxmodificator '{*' rawcode '*}' {[$_[ 1], $ _ [3]]}
# | Idxmodificator memmodificator '{*' rawcode '*}' {[$_[ 1], '$', $ _ [4]]}
;
pnlistid: pnlist id {[$_[ 1], $ _ [2]]}
| Id {[[], $ _ [1]]}
;
pnlist: pointer {[$_[ 1 ],'']}
| Pointer array {[$_[ 1 ],$_[ 2]]}
| Array {['',$_[ 1]]}
;
pointer: '+'
| '-'
| '*'
;
array: '[' id ']' {$ _ [2]}
| '[' Num ']' {$ _ [2]}
;
idxmodificator: '.!'
| ':!'
| '%!'
| '. +'
| ': +'
| '% +'
| '.-'
| ': -'
| '% -'
| '. ^'
| ': ^'
| '% ^'
;
memmodificator: '$'
;
idxtailitem: 'idx' idxitem {[$_[ 2]]}
| 'Idx' '{' idxitemlist '}' {$ _ [3]}
;
optiontailitem: 'option' '{' oplist '}'
| 'Option' opitem
;
#------------------------------------------------- --------
%%
use tblproc;
Основними компонентами цієї граматики є:
· Option - елемент мови, що визначає налаштування до конкретної таблиці.
· Idx блок - це блок, який визначає параметри індексного таблиці.
· Table блок - блок, що визначає таблицю, її запису та індекси.
· 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, ij, 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, ij, 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, ij, 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, ij, 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.
Додати в блог або на сайт

Цей текст може містити помилки.

Програмування, комп'ютери, інформатика і кібернетика | Курсова
102.3кб. | скачати


Схожі роботи:
Проектування і реалізація бази даних
Просопографіческіе бази даних Росії на прикладі баз даних Comandarm і Duma1
Використання електронної таблиці як бази даних Сортування і фільтрація даних в Microsoft Excel
Створення бази даних критичних властивостей речовин в редакторі баз даних MS Access
Візуальний облік вхідних даних інтерфейсу RS-232
Бази даних банки даних загальне поняття
Захист даних і адміністрування бази даних
Бази даних 3
Бази даних
© Усі права захищені
написати до нас