SQLite es una biblioteca ANSI C que implementa un motor de bases de datos pequeño, rápido, autocontenido, de alta fiabilidad, y de funcionalidad SQL completa.
La base de datos SQLite es un archivo de formato estable, multi plataforma, y retro compatible, usada comúnmente para transferir contenido entre sistemas. No requiere configuración adicional ni servidores dedicados.
SQLite es uno de los motores de bases de datos relacionales más conocidos; su compatibilidad y portabilidad la hacen una herramienta ampliamente usada. Un archivo de base de datos SQLite se puede copiar libremente entre sistemas de 32 y 64 bits, así como entre arquitecturas big-endian y little-endian.

SQLite con Conan

Hay múltiples maneras de incluir SQLite en un proyecto; personalmente considero que la forma más sencilla de usar una biblioteca de terceros es por medio de Conan, siempre y cuando esté disponible. En esta publicación sobre Conan como administrador de paquetes se puede ver más sobre cómo usar Conan.

Para incluir SQLite versión 3.33 en un proyecto CMake se crea un archivo conanfile.txt usando el generador cmake_find_package:

# conanfile.txt
[requires]
  sqlite3/3.33.0

[generators]
  cmake_find_package

Se ajusta el CMakeLists.txt para encontrar el paquete, y se enlaza la biblioteca:

# CMakeLists.txt
#...
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_BINARY_DIR})
find_package(SQLite3 REQUIRED)

#...
target_link_libraries(${PROJECT_NAME} PRIVATE SQLite::SQLite3)
target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_17)

Y se incluye el archivo de cabecera:

#include <sqlite3.h>

Conan se encarga de la descarga e instalación, por lo cual los esfuerzos se pueden enfocar más en el proyecto, y menos en el manejo de dependencias.

Un ejemplo básico de su uso es crear una tabla, poblarla, y consultarla.

Sentencias SQL

El primer paso es crear la base de datos lo cual se puede hacer desde un terminal o consola ejecutando:

sqlite3 database.sqlite3

Con el comando anterior se crea el archivo database.sqlite3.
En los siguientes pasos se crea una tabla, después se le insertan valores, y finalmente se consultan esos valores.

DROP TABLE dual;

CREATE TABLE dual 
(
    Col1 varchar2(255),
    Col2 int
);

INSERT INTO "dual" VALUES('valor',10);

SELECT * FROM dual;

Suponiendo que se va a crear solamente una tabla llamada “dual” primero hay que asegurarse de que no exista: DROP se encarga de borrarla si existe.
Luego se crea la tabla dual con las columnas Col1 y Col2.
Se le insertan los valores.
Finalmente se consultan.

SQLite en C++

Para seguir los mismos pasos anteriores en C++:

  1. Se crea la base de datos indicándole un nombre y un handler. Si ya existe la reabre:

     sqlite3* dbHandler = nullptr;
     auto result = sqlite3_open("database.sqlite3", &dbHandler);
    

    Se puede crear una función auxiliar para ejecutar las sentencias

     int runStatement(const char* statement)
     {
       return sqlite3_exec(dbHandler, statement, printCallback, static_cast<void*>(data), &errorMessage);
     }
    
  2. Se verifica que la tabla dual no exista:

     if (runStatement("DROP TABLE dual") != SQLITE_OK)
     {
       std::cerr << "SQL error: " << errorMessage << '\n';
       sqlite3_free(errorMessage);
     }
    
  3. Se crea la tabla:

     const auto create = "CREATE TABLE dual (Col1 varchar2(255), Col2 int);";
        
     if (runStatement(create) != SQLITE_OK)
     {
       std::cerr << "SQL error: " << errorMessage << '\n';
       sqlite3_free(errorMessage);
     }
    
  4. Se le insertan valores:

     const auto insert = "INSERT INTO dual VALUES('valor',10);";
    
     if (runStatement(insert) != SQLITE_OK)
     {
       std::cerr << "SQL error: " << errorMessage << '\n';
       sqlite3_free(errorMessage);
     }
    
  5. Se consulta el contenido de la tabla:

     const auto select = "SELECT * FROM dual;";
    
     if (runStatement(select) != SQLITE_OK)
     {
       std::cerr << "SQL error: " << errorMessage << '\n';
       sqlite3_free(errorMessage);
     }
    
  6. Finalmente se cierra la base de datos:

     sqlite3_close(dbHandler);
    

La base de datos

Al crear la base de datos database.sqlite3 se genera el esquema main con la tabla sqlite_master de manera automática.

Al crear la tabla dual esta queda dentro de ese mismo esquema.

sqlite3db

Conclusiones

Es bastante útil y sencillo usar sqlite3 para crear una base de datos, y vincularla al proyecto es fácil usando Conan; no obstante, el código es más C que C++ y podría tornarse particularmente complejo en sentencias más elaboradas, por ejemplo, al intentar recuperar valores individuales de una columna en particular.
Por fortuna existe una biblioteca llamada SOCI la cual envuelve sqlite3 para hacer más sencilla e intuitiva la programación de SQL en C++ dando la ilusión de que el código queda incrustado, y de la cual se puede ver un ejemplo en la publicación SQL incrustado usando SOCI

Fuentes

  • Acerca de SQLite: Small. Fast. Reliable. Choose any three.
  • Acerca de SQLite3: Version 3 overview.

Deja un comentario