0% encontró este documento útil (0 votos)
8 vistas34 páginas

MySQLen C

Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como DOCX, PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
8 vistas34 páginas

MySQLen C

Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como DOCX, PDF, TXT o lee en línea desde Scribd
Está en la página 1/ 34

MySQL / API para C (1ª parte)

Fecha: febrero 11, 2020Autor/a: tinchicus4 Comentarios


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:

 Estructura basica

 Variables y constantes

 Funciones

 Clases y Objetos

 Apuntadores (este es opcional pero si les interesa)


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!


C++ , MYSQL

MySQL / API para C (2ª parte)

Fecha: febrero 11, 2020Autor/a: tinchicus3 Comentarios


Anuncios

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

obtener los parametros de conexion en el momento de ejecucion.

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

~/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;

}
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

Vector de argumento original:

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

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

$ ./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
Anuncios

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;

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

printf("Nombre del socket: %s\n", socket_name ? socket_name : "(NULL)");


Anuncios

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:


Anuncios

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

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

printf("Nombre del socket: %s\n", socket_name ? socket_name : "(NULL)");


Anuncios

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


Anuncios

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


Anuncios

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
Anuncios

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
Anuncios

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

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

$ ./programs/client4 -h localhost -u usuario -p tutorial

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

del link para saber como.

Tambien podes donar

Es para mantenimiento del sitio, gracias!


MySQL / API para C (3ª parte)

Fecha: febrero 11, 2020Autor/a: tinchicus2 Comentarios


Anuncios

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

void do_disconnect(MYSQL *conn);


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

void print_dashes(MYSQL_RES *res_set);


void process_result_set(MYSQL *conn, MYSQL_RES *res_set);

void process_query(MYSQL *conn, char *query);


Anuncios

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"

#if !defined(MYSQL_VERSION_ID) || MYSQL_VERSION_ID < 32224


#define mysql_field_count mysql_num_fields
#endif

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

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

void print_dashes (MYSQL_RES *res_set)


{
MYSQL_FIELD *field;
unsigned int i,j;
mysql_field_seek(res_set,0);
fputc('+',stdout);
for(i = 0; i < mysql_num_fields(res_set); i++)
{
field = mysql_fetch_field(res_set);
for(j = 0; j < field->max_length + 2;j++)
fputc('-', stdout);
fputc('+',stdout);
}
fputc('\n', stdout);
}

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

nos devolvera las lineas afectadas.

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

explicar la funcion print_dashes():


void print_dashes (MYSQL_RES *res_set)
{
MYSQL_FIELD *field;
unsigned int i,j;
mysql_field_seek(res_set,0);
fputc('+',stdout);
for(i = 0; i < mysql_num_fields(res_set); i++)
{
field = mysql_fetch_field(res_set);
for(j = 0; j < field->max_length + 2;j++)
fputc('-', stdout);
fputc('+',stdout);
}
fputc('\n', stdout);

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

#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;
while(1)
{
char buf[1024];
fprintf(stderr, "query> ");
if (fgets(buf, sizeof(buf), stdin) == NULL)
break;
process_query(conn, buf);
}
do_disconnect(conn);
return 0;

}
Anuncios

Este codigo es similar al client4.c, pueden verlo en este post, pero la unica diferencia sera reemplazar la siguiente linea:

fprintf (stdout, "Haciendo la magia\n");

por el siguiente bucle para ingresar nuestros comando de forma infinita:


while(1)
{
char buf[1024];
fprintf(stderr, "query> ");
if (fgets(buf, sizeof(buf), stdin) == NULL)
break;
process_query(conn, buf);

}
Anuncios

Este bucle generara un prompt donde ingresaremos nuestros comandos, pueden salir con quit o presionando CTRL+D, una vez

compilado tendremos nuestro programa funcionando, les dejo un ejemplo en video

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

del mysql, como pueden ver usamos a use y select.


Anuncios

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

del link para saber como.

Tambien podes donar

Es para mantenimiento del sitio, gracias!

También podría gustarte