Hola, 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, ahora veremos un poco mas profundo la utilizacion de mysql en C. Vamos adelante, en el proximo ejemplo vamos a obtener los parametros de conexion en el momento de ejecucion. Para empezar vamos a ver una funcion llamada load_defaults() para cargar nuestros valores de conexion u otros valores ~/my.cnf, veamos un ejemplo y luego lo explicamos:

show_argv.c

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

char *groups[] = { “client”, NULL };

int main(int argc, char *argv[])
{
int i;
my_init();
printf (“Vector de argumento original:\n”);
for(i=0; i < argc; i++)
printf(“arg %d: %s\n”, i, argv[i]);

load_defaults(“my”, groups, &argc, &argv);

printf (“Vector de argumento modifiado:\n”);
for(i=0; i < argc; i++)
printf(“arg %d: %s\n”, i, argv[i]);

return 0;
}

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
Vector de argumento original:
arg 0: ./show_argv
arg 1: a
arg 2: b

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

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 exactamente lo mismo al anterior, les paso una salida de ejemplo:

Vector de argumento modifiado:
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

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 tenganlo en cuenta 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:

$ ./programs/show_argv -login=true -secure=yes
Vector de argumento original:
arg 0: ./programs/show_argv
arg 1: -login=true
arg 2: -secure=yes
Vector de argumento modifiado:
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

Con este ejemplo podemos dejar ver como enviar parametros y obtenerlos pero ahora procederemos a analizar la informacion recibida veamoslo a traves de este ejemplo:

show_param.c

# include <stdio.h>
# include <stdlib.h>
# include <getopt.h>

char *groups[]={ “client”, NULL };

struct option long_options[] =
{
{“host”, required_argument, NULL, ‘h’},
{“user”, required_argument, NULL, ‘u’},
{“password”, required_argument, NULL, ‘p’},
{“port”, required_argument, NULL, ‘P’},
{“socket”, required_argument, NULL, ‘S’},
{0, 0, 0, 0}
};

int main(int argc, char *argv[])
{
char *host_name = NULL;
char *user_name = NULL;
char *password = NULL;
unsigned int port_num = 0;
char *socket_name = NULL;
int i;
int c, option_index;

my_init();

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);
printf(“Nombre del socket: %s\n”, socket_name ? socket_name : “(NULL)”);

printf(“Vector de argumento original:\n”);
for(i = 0; i < argc; i++)
printf(“arg %d: %s\n”, i , argv[i]);

load_defaults(“my”, groups, &argc, &argv);

printf(“Vector de argumentos modificados despues de load_defaults():\n”);
for(i = 0; i < argc; i++)
printf(“arg %d: %s\n”, i, argv[i]);

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

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);
printf(“Nombre del socket: %s\n”, socket_name ? socket_name : “(NULL)”);

printf(“Vector de argumentos despues de getopt_long():\n”);
for(i = 0; i < argc; i++)
printf(“arg %d: %s\n”, i, argv[i]);

return 0;
}

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);
printf(“Nombre del socket: %s\n”, socket_name ? socket_name : “(NULL)”);

En este caso vamos a imprimir los parametros de conexion seteados al inicio, la salida de este bloque es:

Parametros de conexion originales:
Nombre del host: (NULL)
Nombre del usuario: (NULL)
Contraseña: (NULL)
Numero de puerto: 0
Nombre del socket: (NULL)
Vector de argument original:

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++)
printf(“arg %d: %s\n”, i , argv[i]);

Aca vamos a obtener los parametros informados originalmente, la salida de este bloque es:

Vector de argument original:
arg 0: ./show_param
arg 1: -h
arg 2: otro_host
arg 3: x

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(), esto es como en el caso anterior y obtendremos esta salida:

Vector de argumentos modificados despues de 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

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

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);
printf(“Nombre del socket: %s\n”, socket_name ? socket_name : “(NULL)”);

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:

Parametros de conexion despues del getopt_long():
Nombre del host: otro_host
Nombre del usuario: usuario
Contraseña: secreto
Numero de puerto: 3306
Nombre del socket: /var/run/mysqld/mysqld.sock

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++)
printf(“arg %d: %s\n”, i, argv[i]);

En este bloque nos devolvera los argumentos no procesados por el getopt_long() los cuales fueron cargados por el load_defaults(), les muestro la salida:

Vector de argumentos despues de getopt_long():
arg 0: x

Como ven el unico parametro resultante es aquel no informado en la estructura, despues sigue la opcion de return 0 para salir exitosamente de la funcion y cerrar el programa. La salida completa seria asi:

$ ./show_param -h otro_host x
Parametros de conexion originales:
Nombre del host: (NULL)
Nombre del usuario: (NULL)
Contraseña: (NULL)
Numero de puerto: 0
Nombre del socket: (NULL)
Vector de argument original:
arg 0: ./show_param
arg 1: -h
arg 2: otro_host
arg 3: x
Vector de argumentos modificados despues de 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
Parametros de conexion despues del getopt_long():
Nombre del host: otro_host
Nombre del usuario: usuario
Contraseña: secreto
Numero de puerto: 3306
Nombre del socket: /var/run/mysqld/mysqld.sock
Vector de argumentos despues de getopt_long():
arg 0: x

Hasta aqui vimos como se manipulan los parametros informados en la linea de comando en conjunto con nuestro programa ahora pasemos al siguiente cliente:

client4.c

# include <stdio.h>
# include <string.h>
# include <mysql.h>
# include <getopt.h>
# include “common.h”
# include “common.c”

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

char *groups[] = { “client”, NULL };

struct option long_options[] =
{
{“host”, required_argument, NULL, ‘h’},
{“user”, required_argument, NULL, ‘u’},
{“password”, optional_argument, NULL, ‘p’},
{“port”, required_argument, NULL, ‘P’},
{“socket”, required_argument, NULL, ‘S’},
{0,0,0,0}
};

MYSQL *conn;

int main (int argc, char *argv[])
{
char *host_name = def_host_name;
char *user_name = def_user_name;
char *password = def_password;
unsigned int port_num = def_port_num;
char *socket_name = def_socket_name;
char *db_name = def_db_name;
char passbuf[100];
int ask_password = 0;
int c,option_index = 0;
int i;

my_init();
load_defaults(“my”,groups,&argc,&argv);

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’:
if (!optarg)
ask_password = 1;
else
{
(void) strncpy(passbuf, optarg, sizeof(passbuf)-1);
passbuf[sizeof(passbuf)-1]=’\0′;
password = passbuf;
while(*optarg)
*optarg++ = ‘ ‘;
}
break;
case ‘P’:
port_num = (unsigned int) atoi (optarg);
break;
case ‘S’:
socket_name = optarg;
break;
}
}

argc -= optind;
argv += optind;

if (argc > 0)
{
db_name = argv[0];
–argc;
++argv;
}

if (ask_password)
password = get_tty_password(NULL);

conn = do_connect(host_name, user_name, password, db_name, port_num, socket_name, 0);

if (conn == NULL)
return 1;

fprintf (stdout, “Haciendo la magia\n”);

do_disconnect(conn);
return 1;
}

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:

$ ./programs/client4 -h localhost -u usuario -p tutorial
Enter password:
Haciendo la magia
$

Hasta aqui 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 vamos a agregar la psoibilidad de ejecutar queries dentro nuestro cliente, voy a dejarlo para un tercer post porque debo agregar mas funciones y esto va a ser muy engorroso tambien vamos a modificar algunos archivos de los hechos hasta ahora y es conveniente explicar en cada caso las funciones nuevas y como procesan la informacion. Espero les haya sido util y nos veremos en el proximo post.

Anuncios