Реализована In-Memory СУБД, поддерживающая следующие операции: добавление записи, удаление записи, получение доступа к записи (и как следствие редактирование), открытие/создание/удаление таблицы, также можно итерироваться по записям. Поля данных возможны двух типов: Long и Text.
Архитектура: класс для таблицы Table, TableStruct - класс для структур таблиц; структура записывается в первую строчку файла в виде: type_of_field, name, max_len (максимальная длина задается только для текстовых полей). Записи фиксируются в файле в формате csv.
- dbms.cpp, dbms.hpp
Реализован интерефейс для работы с сокетами в объектно-ориентированном стиле. Программы клиента и сервера приведены в client.cpp и server.cpp соответственно. Клиент считывает строку символов до '\n', после чего передает запрос серверу. Сервер обрабатывает запрос, и отсылает клиенту таблицу-ответ или сообщение об ошибке. Клиент может отправлять несколько запросов по очереди, прекращение работы клиента по EOF. Прекращение работы сервера по терминальным сигналам SIGTERM или SIGINT.
Архитектура сокетов: базовые классы - SocketAddress и BaseSocket, от них наследуются UnSocketAddress (для struct sockaddr_un), ServerSocket, ClientSocket и тд.
- sock_wrap.cpp, sock_wrap.hpp
Реализован интерпретатор подмножества языка SQL. Лексический анализатор (сканнер) считывает символы со стандартного потока ввода и формирует лексемы, парсер проводит синтаксический анализ получаемой последовательности лексем методом рекурсивного спуска по приведенной ниже формальной грамматике (это измененная таким образом исходная грамматика, чтобы к ней был применим РС-метод), формирует запрос во внутреннем представлении (в виде ПОЛИЗа), затем выполняет его.
- Parser.cpp, Parser.hpp, Scanner.cpp, Scanner.hpp
В makefile есть цели для сборки как в основном режиме (make all - компиляция клиента и сервера), так и в тестовом (make test или make test_cov для последующей генерации отчета о покрытии кода при помощи команды make test_code_coverage), все тесты приведены в DerivedTests.cpp (тесты СУБД, сканнера и парсера).
- Test.cpp, Test.hpp, DerivedTests.cpp, DerivedTests.hpp
СУБД обрабатывает запросы к несуществующим полям, не вносит в таблицу текстовое значение, если его длина больше максимальной длины соответствующего текстового поля, также фиксируются различные другие семантические ошибки - генерируя соответствующие исключительные ситуации. Сканнер и парсер также обрабатывают всевозможные лексические, синтаксические и семантические ошибки.
- Exceptions.cpp, Exceptions.hpp, ParameterError.tpp
Обозначения: в двойных кавычках указаны терминалы, заглавными буквами - нетерминалы; запись по типу ("+" | "-") обозначает выбор одной из альтернатив в скобках; { } и [ ] - итерации, в угловых скобках < > указаны действия; eps - пустая цепочка
Грамматика G', полученная из исходной G (приведена в Parser.hpp):
-
START -> "INSERT" INSERT | "CREATE" CREATE | "DROP" DROP | "UPDATE" UPDATE | "SELECT" SELECT | "DELETE" DELETE
-
INSERT -> "INTO" "table_id" "(" FIELD_VAL { "," FIELD_VAL } ")"
-
FIELD_VAL -> "str" | "num"
-
CREATE -> "TABLE" "table_id" "(" "field_id" FIELD_TYPE { "," "field_id" FIELD_TYPE } ")"
-
FIELD_TYPE -> "TEXT" "(" "num" ")" | "LONG"
-
DROP -> "TABLE" "table_id"
-
UPDATE -> "table_id" "SET" "field_id" "=" EXPR "WHERE" WHERE
-
SELECT -> FIELDS "FROM" "table_id" "WHERE" WHERE
-
FIELDS -> "field_id" { "," "field_id" } | "*"
-
DELETE -> "FROM" "table_id" "WHERE" WHERE
-
WHERE -> EXPR_BOOL [<if is_expr==true>[ "NOT" ] OPTION ] | "ALL"
-
OPTION -> "IN" "(" CONST_LIST ")" | <if is_text_field==true> "LIKE" "str"
-
CONST_LIST -> "str" { "," "str" } | "num" { "," "num" }
-
EXPR_BOOL -> BOOL_TERM { "OR" <is_expr=false> BOOL_TERM }
-
BOOL_TERM -> BOOL_MULT { "AND" <is_expr=false> BOOL_MULT }
-
BOOL_MULT -> "NOT" <is_expr=false> BOOL_MULT | EXPR [ ("=" | "!=" | "<" | ">" | "<=" | ">=") <is_expr=false> <if is_inside==false throw err> EXPR ] | "(" <is_inside=true> EXPR_BOOL ")" <is_inside=false>
-
EXPR -> EXPR_LONG | "field_text_id" <is_text_field=true> | "str"
-
EXPR_LONG -> LONG_TERM { ("+"|"-") LONG_TERM }
-
LONG_TERM -> LONG_MULT { ("*"|"/"|"%") LONG_MULT }
-
LONG_MULT -> "field_long_id" | "num" | "(" EXPR_LONG ")"
Данная грамматика G', если не учитывать действия, порождает больший язык, чем L(G), однако засчет действий цепочки из L(G'), не входящие в L(G), считаются синтаксически недопустимыми.