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 dos 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 divido en dos para el descanso de uds. y mio, en este caso sucederá esto porque vi que es mucha información y realmente nos vamos a agobiar con todo la información, sin mas preámbulos empecemos. Para este post en caso de no saber nada de C o C++, les recomiendo visitar estos posts previamente:

Especialmente los tres primeros donde se ve lo mas básico de 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 dos 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):

  • 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 mysqlsudo apt-get install libmysqlclient-dev

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;
}

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)

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, luego pasamos 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.

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 por defecto 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 programs/client1 `mysql_config --cflags --libs`

Esta linea desde el shell, utiliza el código fuente (source/ es el directorio donde estan almacenados los códigos fuentes) client1.c, -o es para linkear y compilar a un programa (programs/ es como el caso anterior un directorio donde se almacenan los programas finales) 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. Volviendo a 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;
}

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 de 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:

mysql_real_connect(), ha fallado:
Error 2002 (Can’t connect to local MySQL server through socket ‘/var/run/mysqld/mysqld.sock’ (2))

Como vemos ahora, 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. Ahora procedamos con nuestro tercer cliente, en este caso vamos a trabajarlos por separados. 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émoslo:

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);
}

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, 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

En el siguiente 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. Hasta aquí todo sobre 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);

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;
}

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. Si uds. necesitan 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

Cuando lo prueben, si los datos son correctos, debería funcionar correctamente y en el ultimo programa (client3) debería mostrar el texto Haciendo Magia. En resumen, hoy hemos dado nuestros primeros pasos entre mysql 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 como 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 el próximo post, nos adentraremos en algunos detalles mas, permitiéndonos hacer un mejor cliente para nuestros queries. Espero les haya sido de utilidad, nos vemos en el próximo post.

 

Anuncios