Реализация реляционной СУБД на C++17 без внешних зависимостей в runtime-коде. Парсит подмножество SQL, выполняет запросы над таблицами в памяти, умеет сохранять и загружать состояние БД в файл. Реализована в виде статической библиотеки с публичным классом SimpleSqlDB.
- DDL:
CREATE TABLE,DROP TABLEс поддержкойPRIMARY KEY - DML:
INSERT INTO ... VALUES,UPDATE ... SET,DELETE FROM - Запросы:
SELECTс фильтрациейWHERE, логическими операторамиAND/OR/NOT, проверкойIS NULL/IS NOT NULL - Соединения:
INNER JOIN,LEFT JOIN,RIGHT JOINдля двух таблиц по условиюON - Типы данных:
BOOL,INT,FLOAT,DOUBLE,VARCHAR(N) - Сериализация: сохранение и загрузка состояния БД в файл
- Результат любого запроса возвращается строкой и может быть выведен в любой поток
- Вложенные подзапросы не поддерживаются
JOINработает только между двумя таблицамиFOREIGN KEYпока не реализован
#include <iostream> #include "SimpleSqlDB.h" int main() { SimpleSqlDB db; std::string create = "CREATE TABLE orders (id INT PRIMARY KEY);"; std::string insert = "INSERT INTO orders (id) VALUES (1), (2), (3);"; std::string select = "SELECT * FROM orders WHERE id > 1;"; std::cout << db.Execute(create); std::cout << db.Execute(insert); std::cout << db.Execute(select); }
В строку Execute можно передать несколько запросов, разделённых ;. Результат выполнения возвращается строкой — её можно вывести, записать в файл, отправить по сети.
Файл config.txt:
CREATE TABLE orders (id INT PRIMARY KEY, order_number VARCHAR(10), customer_id INT, a BOOL); INSERT INTO orders (id, order_number, customer_id, a) VALUES (1, 'ORD001', 101, TRUE), (2, 'ORD002', 102, FALSE), (3, 'ORD003', 101, FALSE); CREATE TABLE customers (id INT PRIMARY KEY, name VARCHAR(50), email VARCHAR(100)); INSERT INTO customers (id, name, email) VALUES (101, 'Dima', 'dima.com'), (102, 'Egor', 'egor.com'), (11, 'Dima', 'dima2.com'), (103, 'Igor', 'igor.com'); SELECT * FROM orders RIGHT JOIN customers ON customers.id = orders.customer_id;
| Категория | Ключевые слова |
|---|---|
| DDL | CREATE TABLE, DROP TABLE, PRIMARY KEY |
| DML | INSERT, INTO, VALUES, UPDATE, DELETE, FROM |
| Запросы | SELECT, WHERE, ON |
| Соединения | INNER JOIN, LEFT JOIN, RIGHT JOIN |
| Логика | AND, OR, NOT, IS, NULL |
| Типы | BOOL, INT, FLOAT, DOUBLE, VARCHAR(N) |
Проект разделён на несколько модулей, каждый из которых собирается как отдельная статическая библиотека:
Database/
├── main.cpp # Демо-приложение
├── lib/
│ ├── SimpleSqlDB.{h,cpp} # Фасад БД: Execute, сериализация, парсинг
│ ├── Table.{h,cpp} # Таблица: хранение строк, операции над данными
│ ├── Column.{h,cpp} # Колонка: имя, тип, ограничения
│ ├── Request.{h,cpp} # Распарсенный запрос: тип, операнды, условия
│ ├── ParseFile.cpp # Считывает SQL-запрос с конфига
│ └── CMakeLists.txt
├── tests/
│ ├── tests.cpp # Тесты на GoogleTest
│ └── CMakeLists.txt
├── config.txt # Пример SQL-скрипта
└── CMakeLists.txt
Публичный API (lib/SimpleSqlDB.h):
class SimpleSqlDB { public: std::string Execute(const std::string& req_str); private: std::vector<Table> tables; int WriteFile(std::filesystem::path file_name); int ReadFile(std::filesystem::path file_name); int Parse(std::vector<std::string>& data, int* i, std::string& res); };
API намеренно минималистичен: на вход — строка с SQL, на выход — строка с результатом. Это делает интеграцию SimpleSqlDB с любым приложением тривиальной.
- C++17
- CMake ≥ 3.23
- STL (
<vector>,<filesystem>,<fstream>, ...) - GoogleTest 1.12.1 — только для тестов, подтягивается через
FetchContent
В runtime-коде библиотеки внешних зависимостей нет.
git clone https://github.com/LomanTrue/Database.git cd Database mkdir build && cd build cmake .. cmake --build .
После сборки в build/ появится исполняемый файл SimpleDatabase — демо-приложение из main.cpp.
Тесты написаны на GoogleTest и подтягиваются автоматически при сборке через FetchContent. Покрытие — основные сценарии работы с таблицами и SQL-запросами.
Пример теста:
TEST(DBTest, WriteAndReadIntoFileOneTable) { SimpleSqlDB x; std::string req1 = "CREATE TABLE orders (id INT PRIMARY KEY,\n" " order_number VARCHAR(10),\n" " customer_id INT, a BOOL); INSERT INTO orders (id, order_number, customer_id, a) VALUES\n" " (1, 'ORD001', 101, TRUE),\n" " (2, 'ORD002', 102, FALSE),\n" " (3, 'ORD003', 101, FALSE);\n" "WRITE '1.txt';"; SimpleSqlDB y; std::string req2 = "READ '1.txt'; " "SELECT * FROM orders;"; ASSERT_EQ(x.Execute(req1), "Table \"orders\" created\nData inserted\nDatabase wrote into a file \"1.txt\"\n"); ASSERT_EQ(y.Execute(req2), "Database read from file \"1.txt\"\n1 ORD001 101 TRUE \n2 ORD002 102 FALSE \n3 ORD003 101 FALSE \n\n"); }
cd build
ctest --output-on-failureили напрямую исполняемым файлом:
./tests/db_tests # Linux / macOS tests\db_tests.exe # Windows