Foto: Eirik Stavelin (Flickr CC-by)
A menudo, nuestros programas necesitan almacenar información (temporal o no) de forma ordenada, rápida y que no nos complique la vida. Luego también necesitamos poder acceder a ella con la misma facilidad. Para eso vale SQLite. Tendremos un pequeño motor de base de datos que con sólo un par de archivos (.h y .c) más un archivo de datos lo tendremos todo listo.
Tabla de contenidos
- 1 Una pequeña introducción
- 2 ¿Quién usa SQLite?
- 3 ¿Dónde me bajo lo necesario?
- 4 Compilar el código
- 5 Hola mundo – Sacando la versión del motor
- 6 Abriendo y cerrando la base de datos
- 7 Nuestra primera consulta : Creando una tabla
- 8 Insertando información en la tabla
- 9 Obteniendo datos de la tabla
- 10 Una pequeña buena práctica
- 11 También podría interesarte....
Una pequeña introducción
SQLite nos proporciona una forma muy sencilla de introducir y eliminar información (si estamos familiarizados con el lenguaje SQL) sin las complicaciones de tener un motor de base de datos corriendo (MySQL, MariaDB, PostreSQL, MSSQL…). Por un lado, al no realizar conexiones, todo debería ir mucho más rápido, en bases de datos relativamente pequeñas se nota. Además, no podremos hacer llamadas de forma remota (como hemos hecho siempre, conectando con el gestor de base de datos), ni tampoco podremos montar clusters ni nada de eso (directamente, seguro que hay algún proyecto por ahí que lo permita). Las instrucciones SQL soportadas no son muchas (comparado con motores grandes) pero en muchísimos casos tendremos suficiente.
¿Quién usa SQLite?
En un primer momento, podríamos no adoptar una tecnología que no esté ampliamente aceptada (es normal, en cualquier momento es desatendida y ¡todo nuestro código a la basura!), y una tecnología que no sea libre (sobre todo para poder estudiarla, para ver que no tenga una cara oculta). Éstas son dos condiciones que pongo personalmente cuando empiezo a trabajar con alguna.
SQLite se usa en muchos programas como Skype, algunos programas de Adobe, Firefox, Chrome, Safari y muchos más. Además, tenemos extensiones para SQLite en muchos lenguajes de programación como Java, Python, PHP, y muchísimos más (Wikipedia)
¿Dónde me bajo lo necesario?
Directamente en la web oficial: SQLite download. Yo siempre descargo sqlite-amalgamation, aquí tenemos todo el sistema sqlite en dos archivos sqlite.h y sqlite.c listos para trabajar.
Si utilizas GNU/Linux, lo más probable es que tu distribución tenga un paquete sqlite y otro sqlite-dev con el código fuente (necesitaremos los dos).
Para los ejemplos cuento con que tenemos sqlite3.h en el mismo directorio que el código de nuestro programa.
Compilar el código
Todos los códigos que pondré en el post se compilan de la misma manera con gcc. Aunque tenemos dos posibilidades. Por un lado podemos incluir sqlite en nuestro ejecutable. Nuestro programa pesará más, pero no será necesario tener la biblioteca instalada. Eso sí, para compilar, necesitamos el archivo sqlite3.c de la amalgama de código de sqlite. Esto lo haremos así:
$ gcc -o ejecutable fuente.c sqlite3.c -ldl -lpthread
(Si usas Windows, necesitarás otras bibliotecas diferentes de dl y phtread).
Por otro lado, si queremos aprovechar la biblioteca dinámica de sqlite3 instalada en nuestro sistema (ya que muchas aplicaciones lo utilizan, ahorramos cerca de 1Mb de código en cada ejecutable), lo podemos hacer de la siguiente manera:
$ gcc -o ejecutable fuente.c -lsqlite3
De esta forma, los ejecutables ocuparán muchísimo menos, pero necesitaremos tener SQLite instalado en nuestro sistema.
Hola mundo – Sacando la versión del motor
Como primer programa, antes de hacer nada con la base de datos, vamos a consultar la versión de SQLite que tenemos. Por ejemplo, si utilizamos la versión de SQLite instalada en el sistema es muy interesante, porque puede que nosotros estemos utilizando características propias de una versión de la biblioteca y debemos asegurarnos de que la versión que tiene el usuario es igual o posterior.
sqversion.c
1 2 3 4 5 6 7 8 9 10 11 12 | #include <stdio.h> #include <stdlib.h> #include "sqlite3.h" int main(int argc, char* argv[]) { printf ("SQLITE LIB Version: %s\n", sqlite3_libversion()); printf ("SQLITE LIB Version (int): %d\n", sqlite3_libversion_number()); if (sqlite3_libversion_number()<3001008) printf ("Lo siento, tu versión de SQLite es muy antigua\n"); } |
En este caso, para visualizar la versión, nos viene bien la forma bonita, a modo de cadena de caracteres, con sus puntos y todo; pero cuando queremos realizar la comparación, nos será mucho más fácil utilizar la forma numérica.
Abriendo y cerrando la base de datos
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | #include <stdio.h> #include <stdlib.h> #include "sqlite3.h" int main(int argc, char* argv[]) { sqlite3 *db; int res; /* Open database */ res = sqlite3_open("test.db", &db); if (res) { fprintf(stderr, "No puedo abrir la base de datos: %s\n", sqlite3_errmsg(db)); exit(0); } else { fprintf(stderr, "Base de datos OK\n"); } sqlite3_close(db); return 0; } |
Este pequeño programa no hace nada… bueno sólo abre y cierra la base de datos, que normalmente se hará con éxito. Si queremos probar un caso en el que falle, así rápidamente, podemos quitar los permisos de lectura:
$ chmod -r test.db
al archivo test.db para que veamos que también puede fallar el programa.
Nuestra primera consulta : Creando una tabla
Podemos usar este pequeño código para empezar creando una tabla. En este ejemplo, vamos a hacer un pequeño log de eventos de nuestro programa, en el que podemos almacenar la marca de tiempo, nivel (si es más o menos crítico), tipo (otro número), y mensaje.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | #include <stdio.h> #include <stdlib.h> #include "sqlite3.h" int main(int argc, char* argv[]) { sqlite3 *db; char *error = 0; int res; char *sql; /* Open database */ res = sqlite3_open("test.db", &db); if (res) { fprintf(stderr, "No puedo abrir la base de datos: %s\n", sqlite3_errmsg(db)); exit(0); } else { fprintf(stderr, "Base de datos OK\n"); } /* Create SQL statement */ sql = "CREATE TABLE events (" "`timestamp` DATETIME, " "`level` NUMBER, " "`type` NUMBER, " "`message` TEXT)"; /* Execute SQL statement */ res = sqlite3_exec(db, sql, NULL, 0, &error); if (res != SQLITE_OK) { fprintf(stderr, "Error: %s\n", error); sqlite3_free(error); } else { fprintf(stdout, "Tabla creada!\n"); } sqlite3_close(db); return 0; } |
De nuevo, si lo ejecutamos, nos dirá que la tabla ha sido creada, y saldrá del programa.
Insertando información en la tabla
Para ello, vamos a cambiar el SQL por lo siguiente:
1 2 3 4 5 6 7 8 | /* STRFTIME('%s','now') - Unix timestamp DATETIME(STRFTIME('%s','now')) = DATETIME('now') but we can operate with the timestamp */ sql = "INSERT INTO events VALUES (DATETIME(STRFTIME('%s','now'), 'unixepoch'), 1, 2, 'This is a test');" "INSERT INTO events VALUES (DATETIME(STRFTIME('%s','now')+86400, 'unixepoch'), 10, 4, 'This is a test again');" "INSERT INTO events VALUES (DATETIME(STRFTIME('%s','now')+86400*2, 'unixepoch'), 100, 8, 'This is a test again x2');" "INSERT INTO events VALUES (DATETIME(STRFTIME('%s','now')+86400*20, 'unixepoch'), 1000, 16, 'This is a test again x3');"; |
Hemos insertado cuatro filas de datos, en las que rellenamos la fecha y hora, ponemos valores numéricos en level y type y un mensaje final.
Me he complicado la vida un poco para poner la fecha y hora, más que nada para que se vayan sumando algunos días y las fechas sean diferentes.
Obteniendo datos de la tabla
Ahora el tema va a ser ligeramente diferente, porque vamos a extraer información en lugar de generarla y, en muchos casos, puede ser gran cantidad de información la que estamos extrayendo. En este caso, cuando llamamos a la función sqlite3_exec(), el tercer parámetro que hasta ahora es NULL, va a ser el nombre de una función de callback encargada de recibir los datos por parte de SQLite, y ya, nosotros veremos lo que hacemos con ellos. La forma de pasar los datos, será parecida a cómo recibe los argumentos (desde la función main()) un programa en C o C++, gracias a dos variables: una que devuelve el número de argumentos recibidos (argc) y otra que recibe el contenido de éstos (argv). Además, tendremos otra variable más que recibirá los nombres de los campos. Esta función será llamada a cada fila recibida.
Podemos hacer algo como esto:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | #include <stdio.h> #include <stdlib.h> #include "sqlite3.h" static int selectCb(void *nada, int argc, char **argv, char **colNames){ int i; for(i=0; i<argc; i++){ printf("%s => %s\n", colNames[i], argv[i]); } printf("\n"); return 0; } int main(int argc, char* argv[]) { sqlite3 *db; char *error = 0; int res; char *sql; /* Open database */ res = sqlite3_open("test.db", &db); if (res) { fprintf(stderr, "No puedo abrir la base de datos: %s\n", sqlite3_errmsg(db)); exit(0); } else { fprintf(stderr, "Base de datos OK\n"); } /* Create SQL statement */ sql = "SELECT * FROM events;"; /* Execute SQL statement */ res = sqlite3_exec(db, sql, selectCb, 0, &error); if (res != SQLITE_OK) { fprintf(stderr, "Error: %s\n", error); sqlite3_free(error); } else { fprintf(stdout, "SELECT Ok!\n"); } sqlite3_close(db); return |
En este caso tendremos una salida completa con todos los valores de la tabla, aunque bien podemos usar WHERE, LIMIT, etc.
Tenemos un argumento curioso para sqlite3_exec(), que directamente he colocado como 0 en todas las peticiones, ese valor será una variable que podemos pasar al callback cada vez que se ejecute, y que puede tomar el valor que queramos (y también recibir, que para eso es un puntero), lo que significa que tenemos muchas más posibilidades, como poner un identificador para decidir qué hacer con la información recibida o crear otra estructura basada en listas enlazadas para almacenar todo el SELECT y poder leerlo tras ejecutar sqlite3_exec() si todo ha ido bien.
Una pequeña buena práctica
Es bueno utilizar llamadas a sqlite3_initialize() cuando vamos a empezar a utilizar la biblioteca. Y a sqlite3_shutdown() cuando terminamos de utilizarla y no vamos a hacerlo más. Es verdad que no hace realmente falta, pero podemos compilar especificando el define SQLITE_OMIT_AUTOINIT, como su nombre indica, no auto-inicializará. No ganaremos excesiva velocidad no inicializando porque sqlite3_initialize() cuando ya está el sistema inicializado no hará nada, pero son llamadas y comprobaciones que podemos hacer y si nuestra aplicación exige mucho uso de SQLite o el sistema es modesto, seguro que se agradece.
Pingback: Usando SQLite en nuestros programas en C/C++ (I) | PlanetaLibre /
Pingback: Usando prepared statements en SQLite en C/C++ /
En mi programa en C estoy usando esta sentencia:
«SELECT * FROM test WHERE idreg BETWEEN ? AND ? ORDER BY ?;»
Los dos primeros parámetros «idreg BETWEEN ? AND ?» funcionan perfectamente pero el tercero «ORDER BY ?» pasa de él, como si no existiera.
He hecho varias pruebas y no lo consigo… Los tres parámetros les asigno el valor con las funciones sqlite3_bind_…().
Qué estoy haciendo mal?
Hola Manu, hasta donde yo sé, al ORDER BY no le puedes poner una ? porque SQLite no es capaz de compilar la sentencia. Precisamente ese es uno de los sitios que no le gustan a SQLite.
Felices fiestas !
Por cierto, Feliz Navidad
Gracias Gaspar, felices fiestas…
Ya me parecía a mi. En MySQL si se puede.
Yo si puedo compilar la sentencia pero siempre me la ordena por el orden natural (rowid). Por favor me puedes dar un enlace donde se explique eso?
Lo dicho felices fiestas y gracia por contestar 😉
Hola, mis felcitaciones por el articulo, es lo que estaba necesitando.
Estoy iniciando con C++ y me veo en la necesidad de crear una «dll» que interactue con mi aplicación, he podido llevar acabo este proyecto y tu articulo me guio para ese.
En lo unico que me estoy estancando es que no se como recuperar los valores de una busqueda. Me seria de gran ayuda que me des algunas recomendaciones.
Desde ya muy agradecido y te animo a que sigas con este tipo de articulos que contribuyen de gran manera.
Atentamente.
Gracias por tu comentario Alex. Puede que te pueda ayudar la segunda parte del post que encuentras aquí: https://poesiabinaria.net/2015/04/usando-sqlite-en-nuestros-programas-en-cc-ii-nueva-interfaz-v2-y-prepared-statements/
¡Ya me vas contando! Un cordial saludo!
Good step you have written of writing content relating to cooperate sense. Better yet good working skills and hope you write more of this soon.
This is excellent article, thank you for the share! This is what I am looking for, hope in future you will continue sharing such an superb work.
Top Gun Jacket UK
Literally Document look at the software yesterday evening still I had produced a lot of emotions relating to this now I needed to read the software once as it is relatively well crafted. chatbots
Step into the enchanting world of movies123, where cinematic wonders await at every turn. Each film on 123movies is a magical journey, offering a diverse tapestry of genres for an unforgettable movie night at home. Immerse yourself in the captivating allure of Movies123, your premier destination for cinematic excellence.
I’ve got not long ago started off some sort of blog site, the internet people produce here possesses served everyone enormously. Appreciate it intended for all of your current time period & do the job. fire kirin login
Wonderful article. The actual publish impacts lots of immediate problems in our culture. All of us cannot be uninvolved in order to these types of problems. This particular publish provides plans as well as ideas. Really educational as well as useful. libri interessanti 2024
Regards for the purpose of post this amazing piece of writing! I recently came across yuor web blog perfect for your preferences. It includes marvelous not to mention advantageous items. Cultivate monetary management give good results! https://bestbeachreviews.com
Great post, and great website. Thanks for the information! изработка на сайтове
Most of the time I don’t make comments on websites, but I’d like to say that this article really forced me to do so. Really nice post! CNC Milling China
I know this is one of the most meaningful information for me. And I’m animated reading your article. But should remark on some general things, the website style is perfect; the articles are great. Thanks for the ton of tangible and attainable help. 더킹플러스카지노
Succeed! It could be one of the most useful blogs we have ever come across on the subject. Excellent info! I’m also an expert in this topic so I can understand your effort very well. Thanks for the huge help. 더킹플러스카지노
I am happy to find your distinguished way of writing the post. Now you make it easy for me to understand and implement the concept. Thank you for the post. 춘천 스웨디시
moviesjoy has a wide-ranging library of movies and TV shows, ranging from classic films to the latest blockbusters. Whether you are a fan of action, romance, comedy, thriller, or any other genre, this platform has got you covered. Additionally, the availability of TV shows allows binge-watchers to immerse themselves in their favorite series.
My spouse and i shocked while using investigation anyone created to choose this certain release outstanding. Amazing task! Visa de Canadá en línea desde Bulgaria
nice bLog! its interesting. thank you for sharing…. private gym Casselberry fl
Cool stuff you have got and you keep update all of us. milky way login
Immerse yourself in the world of online gaming with confidence on our recommended Toto and casino sites. Receive free money, accumulate bonus points, and exchange them for real cash without the risk of scams. Enjoy a secure and thrilling gaming experience. 카지노 꽁머니
This type of message always inspiring and I prefer to read quality content, so happy to find good place to many here in the post, the writing is just great, thanks for the post. Turkiets ambassad i Moçambique
Thanks for taking the time to discuss this, I feel strongly about it and love learning more on this topic. If possible, as you gain expertise, would you mind updating your blog with extra information? It is extremely helpful for me. loafsmagazine
bflix The advent of high-speed internet and advanced digital technologies has paved the way for the rise of online streaming platforms. Services like Netflix, Hulu, and Amazon Prime have become household names,
123Movies, GoMovies, GoStream, MeMovies or 123movieshub was a network of file streaming websites operating from Vietnam which allowed users to watch films movies123
Yes i am totally agreed with this article and i just want say that this article is very nice and very informative article.I will make sure to be reading your blog more. You made a good point but I can’t help but wonder, what about the other side? !!!!!!Thanks 카지노솔루션
Experience the excitement of sports betting at its finest with SBOBET, the go-to platform for discerning enthusiasts worldwide. With SBOBET88, you’ll enjoy a diverse range of betting options, from soccer to basketball and beyond, all delivered with the highest standards of quality and integrity. Join us now and discover a world of endless possibilities. sbobet