Данный проект содержит:
Интерпретатор анализирует и выполняет некоторое подмножество предложений языка SQL. Синтаксический анализ SQL-предложений проводится методом рекурсивного спуска.
и предоставленной библиотеки классов для работы с файлами данных.
Процесс-клиент, принимает запрос к реляционной базе данных, записанный на языке SQL.
Клиентский процесс передает запрос процессу-серверу, который осуществляет поиск в базе
данных в соответствии с запросом и передает результат поиска клиенту.
Клиент получает от пользователя запрос на модельном SQL и, не анализируя его, передает серверу. Сервер анализирует запрос и в случае его корректности выполняет запрос и передает клиенту ответ. Если же запрос некорректен, сервер передает клиенту код ошибки. Клиент выдает пользователю либо ответ на его запрос, либо сообщение об ошибке.
программ.
- Для компиляции напишите "make" в командной строке.
- Перед началом работы программы убедитесь, что в папке с исполняемыми файлами client и server отсутствует файл "mysocket". При корректной работе (без прерывания работы сервера по ctrl+C) файл ysocket удаляется автоматически
- Запустите сначала процесс сервер с помощью ./server, затем в другом параллельном процессе запустите клиента ./client. В начале введите название файла, в который будет записываться результат работы интерпретатора.
- Для работы с базой данных* пишите нужные команды** в процессе клиенте.
- Для просмотра результатов работы базы данных введите в командной строке cat имя_файла.
- Для работы с базой данных без клиент-серверного взаимодейтсвия, а посредством команд в программе tmp.cpp, пропишите в командной строке ./spm.
- Для чистки файлов пропишите в консоли make clear.
- для ознакомления с прицнипом работы базы данных прочтите ReadMe.txt ** примеры команд есть в файле tests.txt
-
Сервер получает от клиента строку, содержащую команду, и запускает интерпретатор с помощью конструктора: Interpreter obj (str);
-
Кoнструктор считывает первое слово из строки: если это слово SELECT, INSERT, UPDATE, DELETE, CREATE или DROP, то вызыаются соответствующие методы интерпретатора (select_sentence() и т.д.), иначе генерируется сообщение об ошибке.
-
Предложения без WHERE-клаузы (create, insert, drop) не требуют дополнительного парсинга и анализируются в цикле непосредственно в командах create_sentence() и т.д.
-
В WHERE-клаузах требуются лексический и синтаксический анализаторы для обработки самих where-клауз, long-выражений (используются в IN-альтернативе и логических выражений), и для регулярных выражений в LIKE-альтернативе. Для каждого случая создан отдельный namespace со своим набором типов лексем и т.д.
-
После обработки выполняются нужные действия, результат записывается в указанный клиентом файл.
ВНИМАНИЕ! В результате работы команд INSERT, UPDATE, DELETE, CREATE и DROP исходная таблица обновляется!
Модельный язык SQL будет включать лишь шесть основных предложений стандарта языка SQL, возможности которых также будут существенно ограничены. Это:
SELECT — выбрать из БД данные, соответствующие запросу;
INSERT — вставить новую строку данных в таблицу;
UPDATE — обновить значения данных в существующей строке;
DELETE — удалить строку из таблицы;
CREATE — создать таблицу;
DROP — уничтожить таблицу.
Когда вызывается программа сервер, она запрашивает у ОС сокет (socket). После получения сокета он связывает с ним некоторое стандартное имя, чтобы программа-клиент могла общаться с сервером через данный сокет по этому имени. После присваивания имени сокету, сервер « слушает» на этом сокете требования связи (запросы) от процессов-клиентов. Когда запрос появляется, сервер может допустить или запретить связь клиента с сервером. Если связь допустима, ОС соединяет клиента с сервером, и сервер получает возможность получать сообщения от клиента и посылать ему ответы так же, как и при использовании механизма информационных каналов.
Клиент также запрашивает у ОС свой сокет для взаимодействия с другим процессом (сервером), а затем сообщает имя сокета, с которым он хотел бы связаться. ОС пытается найти сокет c заданным именем и, если находит его, посылает серверу, слушающему этот сокет, запрос связи. Если сервер допускает связь, ОС создает специальный сокет, соединяющий два процесса, и клиент получает возможность посылать и получать данные от сервера так же, как и при использовании механизма информационных каналов.
Каждая таблица описывается одним файлом данных. Этот файл состоит из двух частей: заголовка, в котором описывается структура таблицы, и собственно записей. Заголовок содержит информацию о числе полей и для каждого поля — его тип ( строковый или длинный целый). Для строковых полей, кроме того, хранится их длина.
Для работы с таблицами реализована следующая функциональность:
— создание новой таблицы,
— удаление существующей таблицы,
— открытие существующей таблицы,
— перемещение по записям таблицы,
— редактирование отдельных записей таблицы,
— добавление новых записей в таблицу,
— удаление существующих записей из таблицы.
В библиотеке dbms.hpp реализованы следующие структуры:
class IField базовый класс для полей разных типов;
class ITextField : public IField класс потомок для полей типа текст;
class ILongField : public IField класс потомок для полей типа long;
class IShortField : public IField класс потомок для полей типа short;
class ITableStruct содержит вектор из типов. По сути
выполняет роль заголовка таблицы, где
хранятся имена колонок и тип колонки;
class ITable основной класс, содержащий информацию
в таблице в виде вектора векторов указателей
на поля IField, в которых содержится ссылка
на нужный класс-потомок.
Класс ITable содержит: 1. Массив text_fields полей ITextField. 2. Массив long_fields полей ILongField. 3. Массив short_fields полей IShortField. 4. Массив массивов fields с номерами. Если мы хотим получить доступ к значению в клетке [i][j], мы должны посмотреть значение fields[i][j], затем посмотреть тип j-го столбца с помощью метода header.GetType(). Далее нужно обратиться к соответствующему массиву по индексу fields[i][j].
Пример:
header | text1 : TEXT | text2 : TEXT | long1 : LONG | short1 : SHORT | text3 : TEXT
0 | --- | --- | 123 | --- | hello
1 | kill | --- | --- | 1 | world
2 | --- | me | 987654 | -1 | ---
3 | \0 | \0 | 0 | --- | please
fields of elements in the text_field array:
"\0"* | "\0"* | "hello" | "kill" | "\0"* | "world" | "\0"* | "me" | "\0"* | "\0" | "\0" | "please"
fields of elements in the long_field array:
123 | 0* | 987654 | 0
fields of elements in the short_field array:
0* | 1 | -1 | 0*
*isInit() = 0, то есть поле не инициализировано
fields:
0 1 0 0 2
3 4 1 1 5
6 7 2 2 8
9 10 3 3 11
__________________________________________________________________
При удалении столбца (пример со столбцом text2):
header | text1 : TEXT | long1 : LONG | short1 : SHORT | text3 : TEXT
0 | --- | 123 | --- | hello
1 | kill | --- | 1 | world
2 | --- | 987654 | -1 | ---
3 | \0 | 0 | --- | please
fields of elements in the text_field array:
"\0"* | "hello" | "kill" | "world" | "\0"* | "\0"* | "\0" | "please"
fields of elements in the long_field array (не меняются):
123 | 0* | 987654 | 0
fields of elements in the short_field array (не меняются):
0* | 1 | -1 | 0*
*isInit() = 0, то есть поле не инициализировано
fields: удалили столбец i типа t. Элементы столбцов типа != t не меняются. В первой строке
элементы столбцов типа t с номером >= i уменьшаются на 1. В строке >1 элементы столбцов
типа t уменьшаются на число, равное порядковому номеру строки.
0 1 0 0 2 0 0 0 1
3 4 1 1 5 => 2 1 1 3
6 7 2 2 8 4 2 2 5
9 10 3 3 11 6 3 3 7
___________________________________________________________________
При добавлении столбца (пример со столбцом newshort) :
header | text1 : TEXT | long1 : LONG | short1 : SHORT | text3 : TEXT | newshort : SHORT
0 | --- | 123 | --- | hello | 1
1 | kill | --- | 1 | world | 2
2 | --- | 987654 | -1 | --- | 3
3 | \0 | 0 | --- | please | 4
fields of elements in the text_field array (не меняются):
"\0"* | "hello" | "kill" | "world" | "\0"* | "\0"* | "\0" | "please"
fields of elements in the long_field array (не меняются):
123 | 0* | 987654 | 0
fields of elements in the short_field array (места 1, 3, 5, 7):
0* | 1 | 1 | 2 | -1 | 3 | 0* | 3
Из примера видно, что если мы хотим вставить колонку с типом t, которой предшествует
k колонок такого же типа t, то мы вставляем поля на k-е место, а потом на каждое (i*n)+k
место, где n - количество колонок типа t в таблице, i - номер линии.
*isInit() = 0, то есть поле не инициализировано
fields: на 1й строке появляется лишь дополнительный элемент, равный k. В строках >1 элементы
столбцов типа t увеличиваются на число, равное порядковому номеру строки (нумерация с 0).
0 0 0 1 0 0 0 1 1
2 1 1 3 => 2 1 2 3 3
4 2 2 5 4 2 4 5 5
6 3 3 7 6 3 6 7 7
-
Инициализация: пустой таблицы ITable(); пустой таблицы с заданной структурой ITable(const ITableStruct &other); конструктор копирования ITable(const ITable &other); импорт из файла ITable(const std::string filename);
-
Импорт таблицы из файла ITable Open(const std::string filename);
-
Добавление текста в ячейку на строке line в колонку с названием title void AddText(const std::string &val, const std::string &title, const size_t line);
-
Добавление числа типа long в ячейку на строке line в колонку с названием title void AddLong(const std::string &val, const std::string &title, const size_t line);
-
Добавление числа типа short в ячейку на строке line в колонку с названием title void AddShort(const std::string &val, const std::string &title, const size_t line);
-
Получение ссылки на элемент текстовой ячейки на строке line в колонке с названием title std::string &GetTextField(const std::string &Name, const size_t line);
-
Получение ссылки на элемент ячейки типа long на строке line в колонке с названием title long &GetLongField(const std::string &Name, const size_t line);
-
Получение ссылки на элемент ячейки типа short на строке line в колонке с названием title short &GetShortField(const std::string &Name, const size_t line);
-
Добавление линии в таблицу void Add_line();
-
Удаление линии из колонки void Delete_line(const size_t line);
-
Добавление колонки в таблицу с заданным типом и названием Name void Add_Column(const Type, const std::string &Name);
-
Удаление колонки из таблицы с заданным типом и названием Name void Delete_Column(const Type, const std::string &);
-
Конвертация в файл void ToFile(const std::string &filename);
-
Перемещение в начало таблицы void ReadFirst();
-
Перемещение на следующую строчку в таблице void ReadNext();
-
Печать заголовка таблицы void Print_field_names();
-
Печать заданной линии void Print_line(const size_t);
-
Печать текущей линии void Print_line();
-
Печать таблицы void Print_table();
-
Инициализация заголовка таблицы: Пустой заголовок ITableStruct(); Конструктор копирования ITableStruct(const ITableStruct &other); Инициализация заголовка с заданным именем ITableStruct(std::string tn); Инициализация заголовка с заданным вектором и массивом названий и типов колонок ITableStruct(std::string tn, std::vector<std::pair<std::string, Type>> fn, size_t fl);
-
Добавление текстового поля void AddText(const std::string &Name);
-
Добавление поля типа long void AddLong(const std::string &Name);
-
Добавление поля типа short void AddShort(const std::string &Name);
-
Удаление поля данного типа с данным названием void DeleteField(const std::string &Name, const Type field_type);
-
Добавление имени таблицы void SetTableName(const std::string &Name);
-
Изменение заголовка таблицы void SetFieldName(const std::string &Name, const std::string &prevName);
-
Возврат типа поля по индексу Type GetType(size_t index);
-
Возврат имени таблицы std::string get_table_name();
-
Возврат строки с заголовками таблицы std::string get_fields_names();
-
Возврат заголовка таблицы по индексу std::string get_field_name(size_t);
-
Возврат количества полей в таблице size_t get_num_fields();
-
Возврат количества текстовых полей в таблице size_t get_num_text_fields();
-
Возврат количества полей типа long в таблице size_t get_num_long_fields();
-
Возврат количества полей типа short в таблице size_t get_num_short_fields();
-
Возврат количества битов, которые занимает заголовок таблицы size_t get_fields_length();
-
Печать заголовка таблицы void print();
S = SEL | INS | UPD | DEL | CR | DR
SEL = 'SELECT' FIELDS 'FROM' id WHERE создает новую таблицу из отобранных строк и столбцов FIELDS = id {, id} | *
INS = 'INSERT INTO' id (F_VAL {, F_VAL}) вставка в конец таблицы F_VAL = STR | longint STR = symbol {symbol}
UPD = 'UPDATE' id 'SET' id '=' EXPR WHERE замена всех строк, удовлетворяющих where-клаузе
DEL = 'DELETE FROM' id WHERE удаление всех строк, удовлетворяющих where-клаузе
CR = 'CREATE TABLE' id (DESCR) создание заголовка таблицы DESCR = DES_F {, DESC_F} DESC_F = id TYPE TYPE = TEXT (unsigned_int) | LONG
DR = 'DROP TABLE' id удаление из файловой системы
WHERE = 'WHERE' TEXT_ID ['NOT'] 'LIKE' STR | EXPR ['NOT'] 'IN' (CONSTS) | 'WHERE' LOG | 'WHERE ALL'
EXPR = LONG_EXPR | TEXT_EXPR CONSTS = STR {, STR} | longint {, longint}
LONG_EXPR = LONG_SUM { S_OP LONG_SUM } S_OP = + | - LONG_SUM = LONG_MULT { M_OP LONG_MULT } M_OP = * | \ | % LONG_MULT = LONG_VAL | (LONG_EXPR) LONG_VAL = id | longint
TEXT_EXPR = id | STR
LOG = LOG_SUM {'OR' LOG_SUM} LOG_SUM = LOG_MULT = 'NOT' LOG_MULT | (LOG) | (RELATION) RELATION = TEXT_REL | LONG_REL TEXT_REL = TEXT_EXPR EVAL TEXT_EXPR LONG_REL = LONG_EXPR EVAL LONG_EXPR EVAL = '=' | '<' | '>' | '>=' | '<=' | '!='