MySQLen C
MySQLen C
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:
Estructura basica
Variables y constantes
Funciones
Clases y Objetos
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:
Mariadb y superiores:
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>
MYSQL *conn;
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
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:
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:
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,
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;
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
common.c
# include <stdio.h>
# include <mysql.h>
# include "common.h"
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
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:
Usuario de conexión
Base a conectarse
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);
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
client3.c
# include <stdio.h>
# include <mysql.h>
# include "common.h"
# include "common.c"
MYSQL *conn;
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
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
Tengo un Patreon donde podes acceder de manera exclusiva a material para este blog antes de ser publicado, sigue los pasos
Sean bienvenidos a mi nuevo post, hoy continuaremos con nuestro post anterior sobre como utilizar mysql con C (o C++), hasta
ahora vimos como conectarnos, desconectarnos, interceptar errores y por ultimo como crear librerias nuevas y llamar nuestras
funciones, en el dia de hoy veremos un poco mas profundo la utilizacion de mysql en C, en el proximo ejemplo vamos a
Nota: Esto que hablaremos a continuacion es para las versiones inferiores a 5.5 de MySQL para las mas nuevas lo veremos en
otro post mas adelante.
Anuncios
Para empezar vamos a ver una funcion llamada load_defaults() para cargar nuestros valores de conexion u otros valores
show_argv.c
# include <stdio.h>
# include <mysql.h>
}
Anuncios
Analicemos este codigo, incluimos las dos librerias estandar de siempre, luego vamos a crear una
variable char llamada groups en ella vamos a agregar la palabra client y luego va el valor NULL porque para las variables del
tipo char siempre van con NULL al final, en el caso de C si fuera C++ se hace automaticamente, luego pasamos a main, cuando
declaramos a main siempre declaramos dos argumentos, no comentados en los posts anteriores porque no eran utilizados,
estos argumentos son argc y argv (entero y array char respectivamente) en el primero se guardara la cantidad de argumentos
informados y en el segundo se guardan los valores informados, observen el primer printf en él imprimiremos la linea de
etiqueta de los argumentos informados cuando ejecutamos el programa, despues viene un for el cual se encargara de leer los
argumentos informados con el programa y a traves de las variables declaradas nos la vuelve a imprimir en pantalla donde %d le
informa el tipo de salida entero y %s del tipo cadena, luego pasamos los parametros definidos, es decir la posicion del array ( i)
y el valor de contenido en el array argv, donde i indicara la posicion del array, la salida seria asi:
$ ./show_argv a b
arg 0: ./show_argv
arg 1: a
arg 2: b
Anuncios
Observen como el primer argumento es el nombre del programa, el segundo argumento es a y el tercero b, tal como se
informo a la hora de ejecutar el programa, una vez pasado este bloque pasemos al siguiente donde primero analizaremos la
siguiente linea:
load_defaults("my", groups, &argc, &argv);
Anuncios
Este funcion se encarga de cargar los valores configurados en ~/.my.cnf (o c:\my.cnf para windows), si no lo tienes creado te
recomiendo ver este post para crearlo y ver su funcionalidad, en este caso el comando llama a my en la primera declaracion,
este es el archivo anteriormente comentado, luego utilizaremos la variable groups creado anteriormente, y por ultimo
pasaremos los punteros argc y argv, esta linea puede ser ejecutada gracias a la llamada hecha en un principio, my_init(), donde
nos permitira ejecutar los comando de conexion al servidor. Una vez realizado esto, ejecutamos otro printf donde tiene una
nueva etiqueta donde imprimiremos los argumentos pero modificados con los datos del load_defaults(), el for hace
arg 0: ./programs/show_argv
arg 1: --port=3306
arg 2: --socket=/var/run/mysqld/mysqld.sock
arg 3: --host=localhost
arg 4: --user=usuario
arg 5: --password=secreto
arg 6: a
arg 7: b
Anuncios
Lo primero ha mostrar son los datos cargados del load_defaults() para luego mostrarnos los argumentos adicionales, y
finalmente hacemos un return 0 para salir del programa, aca vamos a tener los tres parametros declarados en .my.cnf porque
son los datos coincidentes con la etiqueta [client] en el archivo antes mencionado pero tambien nos trajo dos valores no
contenidos en este archivo, estos proceden de la etiqueta [client] del archivo /etc/mysql/my.cnf (este ubicacion es para mi
distribucion de linux) por eso tengan en cuenta esto pero basicamente esta es una forma de obtener parametros de la linea de
comando, y de como cargar parametros a traves del archivo .my.cnf aca les dejo otro ejemplo de salida:
arg 0: ./programs/show_argv
arg 1: -login=true
arg 2: -secure=yes
arg 0: ./programs/show_argv
arg 1: --port=3306
arg 2: --socket=/var/run/mysqld/mysqld.sock
arg 3: --host=localhost
arg 4: --user=usuario
arg 5: --password=secreto
arg 6: -login=true
arg 7: -secure=yes
Anuncios
Con este ejemplo podemos dejar ver como enviar parametros y obtenerlos pero ahora procederemos a analizar la informacion
show_param.c
# include <stdio.h>
# include <stdlib.h>
# include <getopt.h>
}
Anuncios
En este ejemplo, es mas simple de lo que se ve pero como muestra muchos parametros de salida parece complejo pero no lo
es, en este caso no vamos a utilizar la libreria de mysql sino la estandar para los manejos mas basicos (stdio.h) y dos librerias
mas, stdlib.h para el manejo de atoi y getopt.h para utilizar a getopt_long, en mi caso getopt.h estaba incluida dentro de
/etc/include por ende solamente lo invoque como a las otras pero puede suceder que no este en un path por esto te conviene
copiarlo desde su ubicacion hasta el directorio de tu proyecto (o incluirlo en /etc/include), siguiendo con el ejemplo volvemos a
crear un variable groups como en el caso anterior. Vamos a crear una estuctura es muy similar a class pero la diferencia entre
ambas son: class es de tipo privada y struct es publica, para mayor referencia sobre class les sugiero este post, en este struct
vamos a definir algunos parametros para luego ser usados en getopt_long() mas adelante. pasemos al main en este caso
vamos a definir las variables a ser utilizadas para la conexion en todos los casos vamos a asignarles valores NULL o cero segun
corresponda, tambien vamos a crear una para los bucles for (i) y dos para el getopt_long(), en este caso c y option_index,
iniciamos el metodo de conexion my_init() para proceder con la primera rutina para mostrar los valores de la conexion, en este
bloque:
printf("Parametros de conexion originales:\n");
printf("Nombre del host: %s\n", host_name ? host_name : "(NULL)");
printf("Nombre del usuario: %s\n", user_name ? user_name : "(NULL)"); printf("Contraseña: %s\n", password ? password :
"(NULL)");
printf("Numero de puerto: %u\n", port_num);
En este caso vamos a imprimir los parametros de conexion seteados al inicio, la salida de este bloque es:
Contraseña: (NULL)
Numero de puerto: 0
Esto es obtenido gracias a la comparacion en las lineas, por ejemplo host_name ? host_name : «(NULL)», la primera expresion
es la cual va a ser verificada, en caso de ser verdad muestra la primera expresion informada, y en caso contrario (sea falsa)
muestra el valor informado despues de los dos puntos, en este caso como ven la salida es NULL o cero segun corresponda el
caso pero en todos los casos es debido a no tener ningun valor asignado por ende toma el valor FALSE y muestra la segunda
expresion, salvo en numero de puerto donde no existe esta condicion, luego tenemos este bloque:
printf("Vector de argumento original:\n");
for(i = 0; i < argc; i++)
arg 3: x
Anuncios
Esto seria asi si ejecutaramos el programa con la siguiente linea, ./show_param -h otro_host x, ahora en la siguiente linea
ejecutaremos la funcion load_defaults() para cargar los parametros del archivo .my.cnf como vimos en el caso anterior y hace
exactamente lo mismo, ahora verificaremos como se modificaron los argumentos despues de cargados por load_defaults(),
arg 0: ./show_param
arg 1: --port=3306
arg 2: --socket=/var/run/mysqld/mysqld.sock
arg 3: --host=localhost
arg 4: --user=usuario
arg 5: --password=secreto
arg 6: -h
arg 7: otro_host
arg 8: x
Anuncios
Tal como en el ejemplo anterior, volvemos a tener todos los parametros adicionados y por ultimo nuestros tres parametros
ingresados por la linea de comando, ahora veremos el siguiente bloque donde se pone mas interesante:
while((c=getopt_long(argc,argv,"h:p::u:P:S:",long_options,&option_index))!=EOF)
{
switch(c)
{
case 'h':
host_name = optarg;
break;
case 'u':
user_name = optarg;
break;
case 'p':
password = optarg;
break;
case 'P':
port_num = (unsigned int) atoi (optarg);
break;
case 'S':
socket_name = optarg;
break;
}
}
Anuncios
Aca vemos un bucle while donde vamos a chequear si c es distinto de EOF (End Of File), c va a contener el resultado
de getopt_long(), esta funcion va a recibir los parametros argc, argv, las letras asignadas en la estructura del
principio, long_options y por ultimo el puntero de option_index, hablemos un poco de la estructura, primero definimos que iba
a ser para opcion, luego el nombre del array, y luego utilizamos dos llaves({}) una para el array y otra para contener el bloque
en cuestion, en cada uno de los bloques debemos asignar tres parametros a los cuales les paso a detallar: El nombre largo de la
opcion; un valor de la opcion en este caso required_argument pero puede ser tambien optional_argument o no_argument; se
puede usar un puntero o una variable para establecer un valor pero si usamos NULL (como en nuestro caso) establece la
variable optarg con el valor siguiente a este; abreviatura de la opcion es un caracter unico y es utilizada para reemplazar el
nombre largo de la opcion, y por ultimo tenemos una obligatoria con todos los valores en cero para cerrar el array, luego
pasemos a lo siguiente, el switch, en este caso lo haremos contra c y los cases van a corresponder a una de las letras con las
abreviaturas asignadas en la estructura, observen como a cada variable se le asigna el valor de optarg, como dijimos
anteriormente, salvo en el caso donde es P (el numero de puerto) donde lo asignaremos como entero sin signo y atraves
de atoi (es utilizado para convertir valores de cadena a enteros) con el optarg. Una vez finalizado este bucle procederemos con
este bloque:
argc -= optind;
argv += optind;
printf("Parametros de conexion despues del getopt_long():\n");
printf("Nombre del host: %s\n", host_name ? host_name : "(NULL)");
printf("Nombre del usuario: %s\n", user_name ? user_name : "(NULL)");
printf("Contraseña: %s\n", password ? password : "(NULL)");
printf("Numero de puerto: %u\n", port_num);
Observen como asignamos un nuevo valor a argc y argv atraves de optind, indice donde se almacena todos los argumentos
procesados con el bloque anterior, despues como hicimos en el bloque donde mostramos los parametros originales
configurados este hace exactamente lo mismo pero con los parametros modificados en el bloque de getopt_long(), la salida
seria asi:
Contraseña: secreto
Observen como se modifico el host por el informado en la linea de comandos, ahora pasemos al ultimo bloque:
printf("Vector de argumentos despues de getopt_long():\n");
for(i = 0; i < argc; i++)
En este bloque nos devolvera los argumentos no procesados por el getopt_long() los cuales fueron cargados por
arg 0: x
Anuncios
Como ven el unico parametro resultante es aquel no informado en la estructura, despues sigue la opcion de return 0 para salir
$ ./show_param -h otro_host x
Contraseña: (NULL)
Numero de puerto: 0
arg 0: ./show_param
arg 1: -h
arg 2: otro_host
arg 3: x
arg 0: ./show_param
arg 1: --port=3306
arg 2: --socket=/var/run/mysqld/mysqld.sock
arg 3: --host=localhost
arg 4: --user=usuario
arg 5: --password=secreto
arg 6: -h
arg 7: otro_host
arg 8: x
Contraseña: secreto
arg 0: x
Anuncios
Hasta aqui vimos como se manipulan los parametros informados en la linea de comando en conjunto con nuestro programa
client4.c
# include <stdio.h>
# include <string.h>
# include <mysql.h>
# include <getopt.h>
# include "common.h"
# include "common.c"
}
Anuncios
Veamos este ejemplo, aca integramos todo lo visto anteriormente pero hice un par de modificaciones, entre ellas no utilizo la
libreria stdlib.h porque para este ejemplo necesitaba una libreria mas nueva por ende la reemplace por la string.h por una linea
donde mas adelante la necesitaremos, en el principio declaramos los valores por defecto de conexion, esto fue explicado en
este post en client1.c, luego definimos una variable groups y una estructura como vimos en el ejemplo de show_param.c luego
declaramos a conn para la conexion, despues cargamos via load_defaults() los datos del archivo .my.cnf despues utilizamos
el while visto en el ejemplo anterior pero solamente haremos dos modificaciones, en las instancias de letras
del getopt_long() donde despues de p dejaremos un espacio en blanco, en el case de p chequearemos si optarg es igual a nada
seteamos a ask_password igual a 1 de lo contrario extrae la informacion contenida en la variable passbuf , descartando el
ultimo valor que lo declara como array tipo cadena, y este dato lo pasa a password, luego sigue el programa, en caso de no
haber seteado una contraseña y ask_password es distinto a cero y ejecuta la funcion get_tty_password para solicitar una
contraseña para establecer en la variable password, luego utilizaremos el do_connect para conectarnos a la base, esto
explicado en este post, hacemos imprimir un mensaje si todo fue exitoso hasta ahora y luego ejecutamos
un do_disconnect para desconectarnos, devolvemos un return cero para salir exitosamente del programa, esto seria una salida
de ejemplo:
Enter password:
Haciendo la magia
$
Anuncios
En resumen, hoy hemos visto como tomar parametros, como mostrarlos y por ultimo como integrarlo en el client3 para
permitirnos ingresar otros datos de conexion y en caso de no informar ninguno toma de los datos del archivo .my.cnf (en caso
de existir) para ejecutar la conexion, en el proximo post continuaremos mejorando 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
Bienvenidos sean a este nuevo post, hoy finalizaremos nuestra aventura con la API de C, en este post vamos a concretar
nuestro cliente.
Anuncios
Hasta ahora hicimos un cliente con la posibilidad de conectarnos y desconectarnos, interpretar errores y enviar parametros a
traves de la linea de comando en el post anterior, ahora vamos a crear las funciones para procesar el comando informado en la
linea, como formatear el resultado y por ultimo darle la forma del tipo cliente de mysql, estas nuevas funciones las crearemos
dentro del archivo common.c, crearemos los prototipos en common.h y por ultimo generaremos un bucle para ejecutar
nuestros comandos todo el tiempo necesario, pongamos manos a la obra con las nuevas funciones en common.c:
Nota: Todo esto que veremos a continuacion esta pensado para la version MySQL 5.5 o inferiores, para versiones mas
modernas hare un post mas adelante ya que esto no funcionara con Mariadb.
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);
Veamos primero a common.h, donde declararemos nuestro tres nuevos prototipos de las nuevas funciones a incorporar
en common.c, como ven es simplemente escribir el encabezado de la funcion (son las ultiimas tres lineas), ahora veremos el
nuevo codigo ingresado en common.c, lo pasare y luego explicare cada uno de lo nuevos bloques:
common.c
# include <stdio.h>
# include <mysql.h>
# include "common.h"
}
Anuncios
En este caso, vemos como al archivo le vamos a declarar tres nuevas funciones, vamos con la primera funcion
nueva process_query():
void process_query(MYSQL *conn, char *query)
{
MYSQL_RES *res_set;
unsigned int field_count;
if (mysql_query(conn, query) != 0)
{
print_error(conn, "process_query() ha fallado.\n");
return;
}
res_set = mysql_store_result(conn);
if (res_set == NULL )
{
if (mysql_field_count(conn) > 0)
{
print_error(conn,
"Problemas al procesar el conjunto de resultados.\n");
} else {
printf("%lu filas afectadas.\n",
(unsigned long) mysql_affected_rows(conn));
}
} else {
process_result_set(conn, res_set);
mysql_free_result(res_set);
}
}
Anuncios
En esta funcion, vamos a utilizar dos datos: uno va a ser la conexion (conn) y el otro va a ser el query solicitado (query), primero
chequearemos a traves de mysql_query() el query si es distinto a cero, significa un error, devolvera una notificacion de error
por medio de la funcion print_error(), pueden verla en este post, y saliendo de la funcion, en caso contrario ingresara
en res_set el valor obtenido por medio de mysql_store_result(), esta funcion recupera las filas del servidor y crea un conjunto
resultante, en la siguiente linea usaremos un if para chequear si devolvio un resultado o no, luego otro if donde verifica
si mysql_field_count() es mayor a cero en caso de ser afirmativo nos devuelve un error a traves de print_error() de lo contrario
Lo explicado recien es para los comandos donde no hay devolucion, como por ejemplo insert into, volviendo al primer if donde
verificamos si era NULL o no la variable res_set, en caso de no ser NULL procedera a enviar esa variable a la siguiente funcion
para ver, process_result_set(), y luego lo liberaremos. Una vez terminado esto vamos al siguiente bloque y funcion:
void process_result_set(MYSQL *conn, MYSQL_RES *res_set)
{
MYSQL_FIELD *field;
MYSQL_ROW row;
unsigned int i, col_len;
mysql_field_seek(res_set,0);
for(i = 0; i < mysql_num_fields(res_set); i++)
{
field = mysql_fetch_field(res_set);
col_len = strlen(field->name);
if (col_len < field -> max_length)
col_len = field->max_length;
if (col_len < 4 && IS_NOT_NULL(field->flags))
col_len = 4;
field->max_length = col_len;
}
print_dashes(res_set);
fputc('|',stdout);
mysql_field_seek(res_set,0);
for(i = 0; i < mysql_num_fields(res_set); i++)
{
field = mysql_fetch_field(res_set);
printf(" %-*s |", field->max_length, field->name);
}
fputc('\n', stdout);
print_dashes(res_set);
while((row = mysql_fetch_row(res_set)) != NULL)
{
mysql_field_seek(res_set, 0);
fputc('|', stdout);
for(i = 0; i < mysql_num_fields(res_set); i++)
{
field = mysql_fetch_field(res_set);
if (row[i] == NULL)
printf(" %-*s |", field->max_length, "NULL");
else if (IS_NUM(field->type))
printf(" %-*s |", field->max_length, row[i]);
else
printf(" %-*s |", field->max_length, row[i]);
}
fputc('\n', stdout);
}
print_dashes(res_set);
printf("%lu filas regresadas. \n", (unsigned long) mysql_num_rows(res_set));
}
Anuncios
En esta funcion recibiremos dos datos, el de la conexion y el resultado de la funcion anteriormente explicada, declaramos
cuatro variables, luego utilizamos mysql_field_seek(), esta se encargara de ubicar el cursor en la posicion de los campos
informados, luego utilizaremos un bucle for para recalcular el ancho de las columnas, luego utilizaremos la
funcion print_dashes() (luego la explicaremos), imprimos el caracter informado, luego volvemos a utilizar mysql_field_seek(),
con el siguiente for crearemos el encabezado de los campos de la tabla devuelta, volvemos a utilizar el print_dashes() para
usar un while donde extraeremos la informacion almacenada en la variable res_set y sera «formateada» en pantalla, una vez
finalizado el bucle utilizaremos nuevamente print_dashes() e imprimiremos la cantidad de filas regresadas. Ahora pasaremos a
}
Anuncios
Esta funcion es la responsable de dar un formato al resultado como pueden ver es la encargada de ubicar los signos menos (-)
en el ancho del campo, y los signos mas (+) en las esquinas y en el final de cada campo, esta funcion es la mas simple pero una
de las mas potentes porque nos va a permitir mostrar una salida algo mas parecido al cliente oficial de mysql (Mariadb), estos
tres comando podrian haber sido escritos directamente en el codigo fuente del cliente pero muchas veces es una mejor
practica utilizar librerias apartes por permitirnos una mejor depuracion y lograr una mejor visualizacion y menos compleja en el
codigo final, parece mas engorroso pero con el tiempo se transforma en una muy buena practica, ya vimos dos de los tres
archivos ha modificar ahora procederemos con el archivo final, en este caso client5, veamos el siguiente codigo fuente:
client5.c
# include <stdio.h>
# include <string.h>
# include <mysql.h>
# include <getopt.h>
# include "common.h"
# include "common.c"
MYSQL *conn;
}
Anuncios
Este codigo es similar al client4.c, pueden verlo en este post, pero la unica diferencia sera reemplazar la siguiente linea:
}
Anuncios
Este bucle generara un prompt donde ingresaremos nuestros comandos, pueden salir con quit o presionando CTRL+D, una vez
Como pueden ver, si siguieron bien todos los pasos pudimos lograr un cliente muy interesante, donde detecta errores, nos
permite ingresar por parametros, o como en este caso por el archivo .my.cnf, tambien nos permite utilizar todos los comandos
En resumen, hoy hemos visto de manera progresiva el poder de C permitiendo crear aplicaciones de orden local, las cuales
pueden tener una mayor flexibilidad y performance con respecto a otros metodos, si les interesa conocer un poco mas de C/C+
+, les recomiendo seguir mi blog y visitar este post donde estan el listado de todos los posts, espero les haya sido de utilidad
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