This repository is StormByte Database: the C++26 SQL layer of the StormByte suite.
It depends on StormByte-Logger 2.0.0 or newer, which vendors StormByte-String and StormByte Base. Public headers live under StormByte/database/.
One API covers SQLite, PostgreSQL and MariaDB. You do not construct those backends as generic objects. They are base classes: derive your schema, call the backend constructor, prepare statements and hook connect/disconnect there.
The suite is split on purpose. Base, Buffer, Config, Crypto, Logger, Multimedia, Network, String and System are other repositories. This repository does not implement them.
- One connection type —
StormByte::Database::Databasewith Connect / Disconnect, Query / SilentQuery, named prepared statements and RAII transactions. - Inheritance first — SQLite3, MariaDB and Postgres constructors are protected. Your application database is a subclass.
- Values — type-erased
Value(NULL, integers, double, text, blob, bool) with safe numericGet<T>(). - Rows — ordered columns, lookup by name (
ColumnNotFound/OutOfBounds). - Prepared statements — bind by position (0-based),
nullptris SQL NULL,ExpectedRowson execute. - Transactions —
BeginTransaction(IsolationLevel)returnsExpected<Transaction, TransactionError>; failed starts are reported as a value, and an uncommitted transaction rolls back on destruction. - Telemetry —
GetTelemetry()returns a thread-safe, cumulativeStormByte::Sharedhandle with operation counts, outcomes, rows and latency min/mean/max. SQLite, PostgreSQL and MariaDB provide derived telemetry with backend-specific error counters; retained handles remain readable after disconnect/destruction. - TLS —
SslModefor MariaDB and PostgreSQL. SQLite ignores it. - Concurrent access — operations on one connection are serialized; separate connections can run concurrently. A transaction reserves its connection until commit or rollback and must remain on the thread that created it. Custom backend implementations must lock the shared connection mutex in public operations.
| Module | Role | API |
|---|---|---|
| Base | Exceptions, Expected, serialization, strings, UUID, concepts | /StormByte |
| Buffer | FIFO, SharedFIFO, Ring, Producer/Consumer and multi-stage pipelines | /StormByte-Buffer |
| Config | Human-readable text and versioned binary documents (groups, lists, raw bytes) | /StormByte-Config |
| Crypto | Hash, compress, encrypt, sign and key agreement — Crypto++ never leaves the private tree | /StormByte-Crypto |
| Database | This repository | /StormByte-Database |
| Logger | Stream logger with levels, headers, human-readable sizes and redaction (ThreadedLog) |
/StormByte-Logger |
| Multimedia | Decode, encode and containers without raw FFmpeg types; codecs enabled only if present | /StormByte-Multimedia |
| Network | Framed packets, Client/Server, IPv4/IPv6 TCP and Buffer pipelines (compress/encrypt) | /StormByte-Network |
| String | Owned UTF-8 / wide text that can cross a DLL boundary | /StormByte-String |
| System | Processes, pipes and environment variables across Linux, Windows and macOS | /StormByte-System |
- What this module does
- The rest of the suite
- Documentation
- Installation
- Usage
- Telemetry
- Support
- Contributing
- License
Needs a C++26 compiler, CMake 3.28 or newer, and StormByte-Logger 2.0.0 or newer. Logger supplies the bundled StormByte-String and StormByte Base dependencies used by Database. Enable the backends you want (WITH_SQLITE, WITH_POSTGRES, WITH_MARIADB: OFF, SYSTEM or BUNDLED); SYSTEM discovers installed connectors and BUNDLED builds them.
git clone --recurse-submodules https://github.com/StormBytePP/StormByte-Database.git
cd StormByte-Database
cmake -S . -B build
cmake --build buildShared vs static follows CMake BUILD_SHARED_LIBS (default ON). -DBUILD_SHARED_LIBS=OFF builds a static archive. In static mode BuildMaster flattens private vendor dependencies into the consumer link closure; users do not need to repack vendor archives. The shared library keeps Database replaceable as its own DLL/shared object.
- This README: build modes, backend selection, ownership and examples.
- Doxygen class reference: https://dev.stormbyte.org/StormByte-Database/.
Headers are #include <StormByte/database/….hxx>. Namespace root is StormByte::Database.
Moving a connected backend transfers ownership of its connection; the moved-from backend is disconnected.
#include <StormByte/database/sqlite/sqlite3.hxx>
#include <StormByte/logger/log.hxx>
#include <utility>
class AppDb : public StormByte::Database::SQLite::SQLite3 {
public:
AppDb(StormByte::Shared<StormByte::Logger::Log> log)
: SQLite3(std::filesystem::path{"app.db"}, log) {}
protected:
void DoPostConnect() noexcept override {
EnableForeignKeys();
PrepareSTMT("user_by_id", "SELECT id, name FROM users WHERE id = ?");
}
};
int main() {
AppDb db(nullptr);
if (!db.Connect())
return 1;
auto rows = db.Query("SELECT 1 AS n");
if (!rows)
return 1;
}MariaDB / Postgres follow the same pattern: subclass, pass host / user / password / database (and port on MariaDB), optionally SetSslMode before Connect(). PostgreSQL connection parameters are passed separately, so credentials may contain quotes and backslashes.
#include <StormByte/database/value.hxx>
using namespace StormByte::Database;
Value n(42);
Value empty; // SQL NULL
auto i = n.Get<int>();
if (auto row = /* from Query */) {
const Value& name = (*row)[0]["name"];
}Malformed or out-of-range numeric values returned by a backend are reported through ExpectedRows as query errors.
auto result = db.ExecuteSTMT("user_by_id", 7);
if (!result)
return 1;
for (const auto& row : *result) {
auto id = row["id"].Get<int>();
}nullptr binds SQL NULL. Missing statement names raise UnknownSTMT through ExpectedRows.
#include <utility>
{
auto tx_result = db.BeginTransaction(IsolationLevel::Serializable);
if (!tx_result)
return 1;
auto tx = std::move(*tx_result);
db.SilentQuery("INSERT INTO users(name) VALUES ('ada')");
tx.Commit();
} // Rollback if Commit was not called#include <StormByte/database/sqlite/sqlite3.hxx>
#include <iostream>
#include <string>
auto telemetry = db.GetTelemetry();
const auto query_metrics = telemetry->Metrics(StormByte::Database::Operation::Query);
std::cout << "queries=" << query_metrics.Attempts
<< " failures=" << query_metrics.Failures
<< " mean_ns=" << query_metrics.MeanNanoseconds() << '\n';
if (const auto* sqlite = dynamic_cast<const StormByte::Database::SQLite::Telemetry*>(telemetry.get()))
std::cout << "sqlite_busy=" << sqlite->BusyErrors()
<< " constraints=" << sqlite->ConstraintErrors() << '\n';
std::string snapshot = static_cast<std::string>(*telemetry);Telemetry records operation attempts, successes/failures, total/minimum/mean/maximum latency, rows returned, and categorized backend events. It does not retain SQL text or bind values. Its getters are safe to call while operations run; snapshots may reflect updates that complete during the read. The Shared handle owns the same cumulative telemetry object and remains valid after the database is disconnected or destroyed.
Questions and bugs: GitHub issues on this repository. Sponsorship: github.com/sponsors/StormBytePP.
Issues only on this repository. Fork and open a pull request against master.
Dual license: GNU Lesser General Public License v3.0 or later, or a commercial license from the copyright holder. See LICENSE, COPYING.LGPLv3 and https://www.gnu.org/licenses/lgpl-3.0.html. Third-party trees under thirdparty/ keep their own licenses.