|
libsl3 1.3.51003
A C++ interface for SQLite
|
libsl3 enables efficient communication with SQLite3 databases using a natural approach: SQL.
The library does not attempt to function as an ORM (Object-Relational Mapping) and does not introduce C++ syntax resembling SQL for interacting with a SQLite database.
Reading from and writing to a database is accomplished through SQL and prepared statements.
The library fully supports the SQLite duck typing concept, but it also offers a means to incorporate type checking when communicating with a database.
libsl3 started as a C++98 project a long time ago. Later, when C++11 was new, it became a modern C++11 interface to SQLite. Today, libsl3 is still around: a C++ interface for SQLite. Active development happens rarely, but the library is still maintained and updated when required.
Since version 1.2.50004 (tested with SQLite3 3.50.4), the Bazel build system is supported.
This should make it easy to integrate libsl3 into a Bazel project.
For CMake usage, there are various ways to handle dependencies and the build.
With CMake, libsl3 can be built and consumed without any external dependencies, but you might want to use the sqlite3 installation from your system.
One way to consume sl3 is via CMake's FetchContent.
If you want to use the system sqlite3 installation, you can omit the line SET(sl3_USE_INTERNAL_SQLITE3 ON)
Bazel will care about dependencies and build and test the package.
Get your copy of the source code from the libsl3 GitHub repository.
The project has the following dependencies:
There are 3 options for dependency management.
If doxygen is not found, it will not be possible to build the documentation.
See below for how to use either vcpkg or FetchContent.
The library can be built with CMake. No surprises here.
If you use vcpkg, the easiest way to build the library is:
There is also an Xcode preset for macOS, and an MSVC22 preset for Windows.
macOS:
Windows:
If you do not have vcpkg installed, the simplest way to get started is
If you have sqlite3 installed on your system, you can use it by omitting -Dsl3_USE_INTERNAL_SQLITE3=ON.
CMake options to control the build process:
sl3_USE_INTERNAL_SQLITE3: sl3_BUILD_TESTING: For the internal sqlite3 distribution, there are several options to configure sqlite3.
Advantages of using the internal sqlite3
Programs consuming libsl3 do not need to link against sqlite3.
Disadvantages of using the internal sqlite3
All the tests can be found in the tests subdirectory.
Existing tests try to cover as much as possible, see the coverage report for details.
A database is represented via sl3::Database.
A database can execute SQL strings to read or write data.
An sl3::Command is a compiled SQL statement which can contain parameters.
Parameters are sl3::DbValues, a sl3::Container of sl3::DbValue instances.
sl3::DbValues can also be used to receive data from a database.
Requesting data from a database will return a sl3::Dataset with rows of sl3::DbValues where each field is a sl3::DbValue.
Another and fully customizable way to receive data from a database is covered in the RowCallback and Callback functions section.
Since the ostream operator for sl3::DbValue is overloaded, this will print
sl3::Database encapsulates a SQLite database.
It can be used directly, but it also has a virtual destructor and can be used as a base class.
The types in libsl3 are those available in the datatypes SQLite provides.
Since a database value can also be NULL, there is a type for it.
There is one additional sl3::Type.
In SQLite, a column can hold different types, and libsl3 supports this concept.
See sl3::DbValue for more information.
This class can be used to read from and write to a sl3::Database.
An sl3::DbValue can hold different types. You can define whether any type is allowed for an instance or only a specific one.
There are two sl3::Type properties. One defines the type rule, and the other defines the type value.
Both properties are used to validate reads and writes at runtime.
If a value is set or read that is not allowed by the type property, an sl3::ErrTypeMisMatch exception is thrown.
Setting a value can be done via
sl3::DbValue::setNull can be used to set a value to Null.
There are getters for each type:
There are two versions of each of these functions. With and without a default value as argument.
The version without a default value will throw a sl3::ErrNullValueAccess exception if sl3::DbValue::isNull is true for the instance.
The version with a default value as argument will return the passed argument if the current sl3::DbValue::isNull is true.
If a type getter is used for the wrong storage type, a sl3::ErrTypeMisMatch exception is thrown.
Additionally, there is a sl3::DbValue::get version which will never throw.
This function always requires a default value which has to be one of the four value types.
If the type is incorrect or the value is Null, the given default value will be returned.
This example will print
An sl3::Command is a compiled SQL statement which can contain parameters.
sl3::Database::prepare creates a command.
If a command has parameters the types are specified at creation.
A command can return data or not, depending on the SQL that is used.
An insert or update statement does not return data, while a select statement does.
A command therefore has 2 ways to run it.
In the A first example overview example, all sl3::Command parameters were of type sl3::Type::Variant since nothing was specified.
But it can be ensured that certain types are used.
The output of this program will be:
It is not a problem to insert different types into a column; SQLite supports this, and so does libsl3.
But it might be unwanted and can therefore be turned off.
A sl3::Dataset is a generic way to receive data from a sl3::Database.
It is returned by sl3::Command::select or sl3::Database::select.
If there are different types in a column, a sl3::Dataset will automatically provide the correct sl3::DbValue objects.
Running this program will print
It might be undesirable to get different types for one column into a sl3::Dataset.
This can be ensured by passing the allowed sl3::Types to the sl3::Database::select call.
If the requested types are not those in the table, an sl3::TypeMisMatch exception is thrown.
This code will throw an exception, as expected, and print
A custom way to handle query results is to use an sl3::RowCallback or the sl3::Command::Callback function.
They can be passed to sl3::Database::execute and sl3::Command::execute functions.
The callback will be called with an sl3::Columns representing the current row for each row in the query result.
The callback returns whether it should be called again.
In a callback, the sl3::Columns class gives access to the current row.
There are several methods to query the type, size, and values.
Running this program, the output will be