Anuncios

Hola, bienvenidos sean a mi nuevo post. Hoy hablaremos sobre la API de C para conectarse a mysql, en este caso ya tengo decidido hacerlo en tres partes porque habitualmente si no es muy extenso y desgastador trato de dejar los temas en un solo post pero cuando se vuelve largo y tedioso, lo dividi en varias partes para el descanso de ustedes y mio 😁, en este caso sucederá esto porque vi que es mucha información y realmente nos vamos a agobiar con toda ella.

Anuncios

Para esta serie de posts en caso de no saber nada de C o C++, les recomiendo visitar estos posts previamente:

Anuncios

Especialmente los tres primeros donde se ve lo mas básico de C y C++, esto obviamente para no estar desorientados en los códigos fuentes desarrollados en estos posts, la idea es realizar algo progresivo es decir empezar con un código donde simplemente se conecte al servidor y se desconecte, luego ir manipulando errores, despues incorporar codigo modular y reutilizable, permitir aceptar datos de conexión para la misma y por ultimo tener un cliente similar al de mysql para ejecutar nuestros queries, se que suena ambicioso pero esperemos al final de estos tres posts tener un cliente alternativo y sobre todo poder adquirir los conocimientos para poder crear nuestras propias aplicaciones y obtener información de mysql, antes de pasar a nuestro primer código, debemos de hacer un par de pasos para no tener ningún error en el momento de compilarlo, esto es en una distribución de Debian (Linux), esto debemos hacerlo en nuestro servidor de la base de datos que hicimos en este post:

  • Primero actualicen el cache de los paquetes de APT-GET con el comando:
    sudo apt-get update (En el caso de no ser root).
  • Luego deben instalar el paquete de C++, para esto ejecuten:
    sudo apt-get install build-essential
    Una vez finalizado podran compilar los codigos fuentes
  • Y finalmente deberan instalar el paquete de desarrollo de mysql
    Mysql 5.5 y anteriores:
    sudo apt-get install libmysqlclient-dev
    Mariadb y superiores:
    sudo apt-get install libmariadb-dev libmariadb-dev-compat
Anuncios

Una vez instalado todos estos paquetes ya podrán compilar los códigos fuentes de los posts, una vez aclarado esto pasemos a la acción:

client1.c

# include <stdio.h>
# include <mysql.h>

#define def_host_name NULL
#define def_user_name NULL
#define def_password NULL
#define def_db_name NULL

MYSQL *conn;

int main (int argc, char *argv[])
{
 	conn = mysql_init (NULL);
 	mysql_real_connect(conn,
 			def_host_name,
 			def_user_name,
 			def_password,
 			def_db_name,
 			0,
 			NULL,
 			0);
 	mysql_close(conn);
 	return 0;
}
Anuncios

Este es el código de nuestro primer programa, es bien simple donde solamente vemos como se incluyen dos librerías: stdio.h y mysql.h. Las cuales nos permitirán utilizar el resto de las funciones, después declararemos cuatro valores constantes, estos son en el mismo orden para:

  • Establecer el server. (def_host_name)
  • Establecer el usuario. (def_user_name)
  • Establecer la contraseña. (def_password)
  • Establecer la base a conectarnos. (def_db_name)
Anuncios

En este primer ejemplo lo definimos como NULL a todos y cada uno de ellos. Después crearemos un apuntador del tipo de dato MYSQL (este es proveniente de la librería mysql.h) para el manipulador de la conexión, nuestro siguiente paso es ver al cuerpo de main(). Aqui vamos ha asignarle un método al apuntador conn, mysql_init(null) para iniciar la conexión, y luego vamos a ejecutar el método mysql_real_connect(), el cual se va a inicializar con los valores de:

  • Apuntador de conexion, este nos permitira iniciar la conexion.
  • Host del server, la direccion IP o hostname del server.
  • Usuario para la conexion.
  • Contraseña del usuario antes citado.
  • La base de datos a administrar
  • Puerto de conexion, en caso de ser 0 se utiliza el predeterminado (recomendable).
  • Socket, idem al anterior en valor NULL se usa el predeterminado.
  • Modificadores, en este caso ninguno.
Anuncios

Como pueden ver, en el mysql_real_connect() utilizamos todos los valores establecidos previamente, ya sea el host, usuario, clave y base. Después tenemos dos valores, uno del puerto y otro el socket, en caso de ser distintos a los predeterminados por mysql, se debería ingresar esos valores y por el contrario en caso de no haber sido modificados y se utilizan los predeterminados provenientes de la instalación de mysql se deberían utilizar los indicados en el ejemplo pero tengan en cuenta ante una probable falla o error también estos parámetros pueden ser determinantes, una vez finalizados procedemos a cerrar la conexión almacenada en el apuntador (conn) y por ultimo retornamos un cero el cual es utilizado para indicar una buena salida sin ningún error, para compilarlo les recomiendo la siguiente linea:

gcc source/client1.c -o program/client1 `mysql_config --cflags --libs`
Nota: Para un mejor organizacion en el directorio de trabajo de mi equipo tengo una subcarpeta llamada source para los codigos y otra llamada program para los codigo compilados, esto es recomendable pero no obligatorio y dependiendo del criterio de cada uno.
Anuncios

Esta linea desde el shell, utiliza el código fuente client1.c, -o es para linkear y compilar a un programa con el nombre client1 pero la siguiente opción entre acento grave (`) es para obtener todos los datos de las librerías y así el compilador gcc permite un correcto funcionamiento y vinculación con las librerías y el programa, hay otro método pero este fue el de mejores resultados por esto les recomiendo utilizarlo de esta manera continuando con nuestro programa, si pudieron compilarlo con éxito habrán observado el resultado final, no hace nada. No se preocupen eso es correcto porque si analizan el programa no ejecuta nada, solamente se conecta y desconecta del server y a su vez no le informamos ningún parámetro (host, usuario, clave, base)​, por esto vamos a pasar a nuestro segundo código donde vamos a agregar verificadores de errores, pasemos al código de client2:

client2.c

# include <stdio.h>
# include <mysql.h>

#define def_host_name NULL
#define def_user_name NULL
#define def_password NULL
#define def_db_name NULL

MYSQL *conn;

int main (int argc, char *argv[])
{
  conn = mysql_init (NULL);
  if (conn == NULL)
  {
 	fprintf (stderr, 
		"mysql_init() ha fallado (seguramente por falta de memoria\n");
 	return 1;
  }
  if (mysql_real_connect(conn,
		def_host_name,
		def_user_name,
		def_password,
		def_db_name,
		0,
		NULL,
		0)==NULL)
  {
 	fprintf(stderr,"mysql_real_connect(), ha fallado: \nError %u (%s)\n",
				mysql_errno(conn), 
				mysql_error(conn));
 	return 1;
  }
  mysql_close(conn);
  return 0;
}
Anuncios

En este nuevo código, solamente agregamos un par de variantes a nuestro primer código, desde el principio haremos exactamente lo mismo, el primer nuevo bloque es después de la linea donde seteamos a conn. En este bloque verificaremos a través de un if si el valor conn es igual a NULL, en caso de ser verdad nos despliega un mensaje de error y nosotros retornaremos el valor uno saliendo del programa, en caso contrario, continua el programa, nuestra siguiente modificación es agregar a través de otro if que el valor devuelto por mysql_real_connect() sea igual a NULL, en caso de ser afirmativo nos desplegara un mensaje de error, retornando el valor uno para después salir del programa. en caso contrario continua con el programa y procede con e cierre de la conexión. Ahora si nosotros compilamos el programa y lo ejecutamos vamos a tener la siguiente salida:

tinchicus@dbn001vrt:~/lenguajes/mysql/c$ gcc source/client2.c -o program/client2 mysql_config --cflags --libs
tinchicus@dbn001vrt:~/lenguajes/mysql/c$ ./program/client2
mysql_real_connect(), ha fallado:
Error 1045 (Access denied for user 'tinchicus'@'localhost' (using password: NO))
tinchicus@dbn001vrt:~/lenguajes/mysql/c$
Anuncios

Como vemos en la salida a diferencia del programa anterior, ahora si vamos a tener una salida y como dijimos anteriormente en el código no informamos ningún dato por esto al ejecutarlo nos devolverá el error antes mostrado, ahora si modificaran los datos de conexión (def_host_name, def_user_name, def_password, def_db_name) a unos correctos no debería traernos ningún mensaje de error. Hasta aquí establecimos nuestra primera conexión, desconexión y también verificamos el estado de la conexión, pasemos con nuestro tercer cliente, en este caso vamos a trabajar el codigo por separado, es decir vamos a tener el código fuente del cliente, y a su vez una librería con las funciones mas comunes desarrolladas y utilizadas por nosotros, pasemos a ver los cdigos y analicémos cada uno de ellos:

common.c

# include <stdio.h>
# include <mysql.h>
# include "common.h"

void print_error (MYSQL *conn, char *message)
{
 	fprintf (stderr, "%s\n", message);
 	if (conn != NULL)
 	{
 		fprintf(stderr, "Error %u (%s)\n", 
			mysql_errno(conn), 
			mysql_error(conn));
 	}
}

MYSQL *do_connect(char *host_name,
 		char *user_name,
 		char *password,
 		char *db_name,
 		unsigned int port_num,
 		char *socket_name,
 		unsigned int flags)
{
 	MYSQL *conn;
 	conn = mysql_init(NULL);
 	if (conn == NULL)
 	{
 	print_error(NULL, 
		"mysql_init() ha fallado (seguramente por problema de memoria)");
 	return NULL;
 	}
 
	#if defined(MYSQL_VERSION_ID) && MYSQL_VERSION_ID >= 32200
 	if (mysql_real_connect(conn, 
				host_name, 
				user_name, 
				password,
 				db_name, 
				port_num, 
				socket_name, 
				flags) == NULL)
 	{
 		print_error(conn, "mysql_real_connect() ha fallado.\n");
 		return NULL;
 	}
 	#else
 	if (mysql_real_connect(conn, 
				host_name, 
				user_name, 
				password,
	 			port_num, 
				socket_name, 
				flags) == NULL)
 	{
 		print_error(conn,"mysql_real_connect() ha fallado.\n");
 		return NULL;
 	}
	if (db_name!=NULL)
 	{
 		if (mysql_select_db(conn,db_name) != 0)
 		{
 			print_error(conn, "mysql_select_db() ha fallado.\n");
 			mysql_close(conn);
 			return NULL;
 		}
 	}
 	#endif
 	return conn;
}

void do_disconnect(MYSQL *conn)
{
 	mysql_close(conn);
}
Anuncios

Esta es la librería «magica», todo el proceso se centrara acá, en esta librería nos encargaremos de conectarnos y desconectarnos del server, también tendrá una función de error y haremos un chequeo por si debemos conectarnos con versiones viejas de mysql.

Empecemos con las tres librerías a incluir, las dos primeras son las de siempre para interactuar con nuestro hardware y con mysql pero a su vez ahora agregamos una nueva llamada common.h, de la cual veremos luego, la primera función es la encargada de manipular los mensajes de error, esto es una buena practica porque como veremos mas adelante repetiremos mucho el llamado a esta función y en caso de tener la necesidad de modificar el mensaje de error, es preferible hacerlo una vez y no en todos los lugares donde este el manipulador de error, la función es bien simple, recibe el manipulador de conexión y el mensaje ha mostrar, después en la primera linea escribe el mensaje de error y en caso de no haber tenido una conexión NULL procede con el siguiente error y despliega una descripción con el código de error y la descripción del mismo. Ahora proseguimos con la función para efectuar la conexión con el server, en esta funcion vamos a recibir todos estos parámetros:

  • Dirección del host
  • Usuario de conexión
  • Contraseña del usuario
  • Base a conectarse
  • Número del puerto
  • Nombre del socket
  • Modificadores
Anuncios

En la siguiente linea creamos el apuntador conn para iniciar al manipulador de conexión, aquí chequeamos si la conexión es NULL o no, en caso afirmativo procede a notificarnos con la función print_error() y luego sale del programa. En caso contrario continua con el mismo, como dijimos anteriormente ahora vamos a chequear si la versión del mysql es superior a la 3.22, esto lo hacemos a traves de MYSQL_VERSION_ID con un condicional if, en caso de ser afirmativo (es decir MYSQL_VERSION_ID >= 32200) procede a ejecutar el mysql_real_connect() como lo veníamos utilizando con todos los parámetros, en caso contrario si utiliza una versión mas vieja ejecuta un mysql_real_connect() omitiendo el parámetro de la base de datos, esto es porque en versiones anteriores a 3.22 no estaba implementado y al ejecutar el mysql_real_connect() nos puede generar un error al intentar conectarnos, si todo sale bien y se conecta luego emulamos una verificación de conexión a la base de datos a través del mysql_select_db(), donde verificamos si es distinto de cero (esto significa la presencia de un error) y llama a la función de print_error() y sale del programa, en caso de funcionar correctamente sigue con el programa y retorna el valor de conn, la siguiente función es do_disconnect() donde solamente recibe a conn para efectuar la desconexión, mysql_close() se encarga de hacer todas las liberaciones pertinentes y procede con la desconexión del server, con esto cubirmos la libreria common.c, ahora continuemos con la siguiente librería:

common.h

MYSQL * do_connect(char *host_name,
 		char *user_name,
 		char *password,
 		char *db_name,
 		unsigned int port_num,
 		char *socket_name,
 		unsigned int flags);

void do_disconnect(MYSQL *conn);

void print_error(MYSQL *conn, char *message);
Anuncios

En esta librería solamente vamos a declarar los prototipos de la librería anterior, como ven es solamente el tipo de dato, el nombre de la función y los parámetros ha recibir por los mismos, esta la salvan como common.h y nada mas, ahora procederemos con el código del cliente, pasemos al ultimo código:

client3.c

# include <stdio.h>
# include <mysql.h>
# include "common.h"
# include "common.c"

#define def_host_name NULL
#define def_user_name NULL
#define def_password NULL
#define def_db_name NULL
#define def_port_num 0
#define def_socket_name NULL

MYSQL *conn;

int main (int argc, char *argv[])
{
 	conn = do_connect(def_host_name, 
			def_user_name, 
			def_password, 
			def_db_name, 
			def_port_num, 
			def_socket_name, 
			0);
 	if (conn == NULL)
 		return 1;
 	fprintf (stdout, "Haciendo Magia\n");
 	do_disconnect(conn);
 	return 0;
}
Anuncios

Como pueden ver, desaparecieron algunas lineas y funciones pero se agregaron otras. En el inicio tenemos las librerías de siempre (stdio.h y mysql.h) pero ahora incluimos las propias, common.c y common.h, esto nos permitira incluir nuestras nuevas funciones (do_connect() y do_disconnect()), también declaramos nuevos parámetros de conexión: port number, socket name y flags, luego creamos el apuntador conn. con este apuntador utilizaremos la función do_connect(), procesara todos los parámetros enviados a la función, después chequeamos si conn es NULL o no, en caso de ser afirmativo retorna uno y procede a salir del programa, en caso contrario imprime un texto, en realidad deberían ir las funciones a ejecutar pero por ahora sera solo eso, luego llama a do_disconnect() y luego retorna cero procediendo con la salida exitosa del programa. Como vieron el código del programa quedo mucho mas simplificado con respecto al client2, especialmente, donde solamente haremos invocaciones a través de las librerías incluidas. Un ultimo dato sobre el ultimo código fuente, en C el condicional if toma como linea propia la primera por debajo de la condición y al resto no, para incluir mas lineas en gral. se utilizan las llaves ({}) donde se guarda en bloque por eso retorna uno solamente si verifica como afirmativo el valor NULL de conn, en caso de que necesiten verificar, como fue mi caso, el correcto funcionamiento de los códigos del post, les recomiendo hacer estas modificaciones en las siguientes lineas:

# define def_host_name «direccion del server«
# define def_user_name «usuario«
# define def_password «contraseña«
# define def_db_name «tutorial«

Anuncios

Para la primera constante pueden usar localhost o 127.0.0.1 (recuerden que estamos en el mismo que la base), las siguientes lineas deberian usar el usuario y contraseña que vimos en posts anteriores y por ultimo es la base que vinimos utilizando hasta ahora, si todos los datos son correctos debería funcionar correctamente y devolver una salida como esta:

tinchicus@dbn001vrt:~/lenguajes/mysql/c$ gcc source/client3.c -o program/client3 `mysql_config --cflags --libs`
tinchicus@dbn001vrt:~/lenguajes/mysql/c$ ./program/client3
Haciendo Magia
tinchicus@dbn001vrt:~/lenguajes/mysql/c$
Anuncios

En resumen, hoy hemos dado nuestros primeros pasos entre mysql (mariaDB) y C, como instalarlo (por lo menos en Linux) para poder tener acceso a las librerías para vincularlos, hemos visto nuestros primeros códigos fuentes para incluir librerías, algo de la estructura de lenguaje, como declarar funciones y como llamarlas, hemos pasado de solamente conectarnos y desconectarnos, a detectar errores y mostrarlos y por sobre todo como agregar nuevas librerías, para llamar y ejecutar las funciones creadas por nosotros, en los proximos posts iremos agregando mas complejidad a nuestro «cliente», espero les haya sido util sigueme en tumblr, Twitter o Facebook para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.

Anuncios

Tengo un Patreon donde podes acceder de manera exclusiva a material para este blog antes de ser publicado, sigue los pasos del link para saber como.

Tambien podes donar

Es para mantenimiento del sitio, gracias!

$1.50

Anuncio publicitario