Реализация реляционной СУБД на 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