Autor : ACMhUnTeR
Fecha : 21/06/2004
Este manual permite dar una introducción al uso de la API en C de MYSQL, para programar aplicaciones escritas en C y realizar cualquiera tarea utilizando nuestra Base de Datos MySQL.
Empezaremos explicando el uso de las estructuras que utilizaremos en nuestro pequeña aplicación.
Estructura que representa la conexión hacia nuestra base de datos.
Estructura que representa el resultado obtenido de algun query realizado a la base de datos.
Estructura que representa las filas de datos, los cuales estan almacenados en un arreglo, estos datos son obtenidos utilizando la funcion mysql_fetch_row.
Dare una breve explicación de las funciones que utilizaremos en la elaboración de nuestro ejemplo utilizando la API.
Inicia el objeto de la estructura MYSQL que sera utilizado para realizar la conexion utilizando la funcion mysql_real_connect().
Realiza una conexion hacia nuestra base de datos MySQL.
Finaliza una conexion abierta.
Captura el error provocado por accion del alguna de las funciones.
Se utiliza para seleccionar una base de datos
Se utilizara para realizar una consulta hacia la base de datos.
Capturara el resultado devuelto por la ejecucion de algun query.
Captura las filas de un resultado obtnido por mysql_store_result.
Libera de memoria el resultado guardado capturado por la funcion mysql_store_result.
Captura el numero de filas afectadas por la ejecucion de un query.
Para explicar el uso de la API en C de MySQL debemos tener instalado nuestro servidor y el cliente de MySQL, estos a la vez instalaran las librerias necesarias para su uso, pueden personalizar a su gusto la instalacion de MySQL pero ya ese es otro tema :).
HellFire# cd /usr/ports/databases/mysql40-server && make install clean clean-depends
Una vez instalado MySQL, iniciaremos el demonio.
HellFire#sh /usr/local/etc/rc.d/mysql-server.sh start
HellFire# cd /usr/pkg/databases/mysql4-server && bmake install clean clean-depends
Una vez instalado MySQL, iniciaremos el demonio.
HellFire#sh /usr/pkg/etc/rc.d/mysqld.sh start
HellFire# cd /usr/ports/databases/mysql && make install clean clean-depends
Una vez instalado MySQL, iniciaremos el demonio.
HellFire# sh /usr/local/bin/mysql-safe
Recomendado asignarle un password al usuario root, ejecutar el comando que pongo a continuación, cuando pida el ingreso de password solo darle a Enter y el nuevo password sera el que especificamos en las comillas simples, ya que por defecto usuario root no tiene asignado un password.
HellFire# mysqladmin -u root -p password 'PasswordAqui'
Una vez iniciado el demonio, probaremos un programa que elabore de una operación ficticia, que genera reportes en html, de los montos obtenidos por la venta de productos, estos datos son obtenidos de nuestro MySQL, para esto creamos 3 tablas en la base de datos que elijamos e ingresaremos datos en cada una de las tablas, creo que la mejor manera de explicar el manejo de la API en C de MySQL es con un ejemplo.
############################################################################################ # Tabla Clientes CREATE TABLE `Clientes` ( `CodClien` VARCHAR(8) NOT NULL DEFAULT '', `NomClien` mediumtext NOT NULL, `ApeClien` mediumtext NOT NULL, `DireClien` mediumtext NOT NULL, `TeleClien` tinytext NOT NULL, KEY `CodClien` (`CodClien`) ) TYPE=MyISAM; # Datos Tabla Clientes INSERT INTO `Clientes` VALUES ('00000001', 'Nombre1', 'Appellido1', 'Direccion1', '111111'); INSERT INTO `Clientes` VALUES ('00000002', 'Nombre2', 'Appellido2', 'Direccion2', '222222'); INSERT INTO `Clientes` VALUES ('00000003', 'Nombre3', 'Appellido3', 'Direccion3', '333333'); INSERT INTO `Clientes` VALUES ('00000004', 'Nombre4', 'Appellido4', 'Direccion4', '444444'); INSERT INTO `Clientes` VALUES ('00000005', 'Nombre5', 'Appellido5', 'Direccion5', '555555'); INSERT INTO `Clientes` VALUES ('00000006', 'Nombre6', 'Appellido6', 'Direccion6', '666666'); INSERT INTO `Clientes` VALUES ('00000007', 'Nombre7', 'Appellido7', 'Direccion7', '777777'); INSERT INTO `Clientes` VALUES ('00000008', 'Nombre8', 'Appellido8', 'Direccion8', '888888'); INSERT INTO `Clientes` VALUES ('00000009', 'Nombre9', 'Appellido9', 'Direccion9', '999999'); # Tabla Productos CREATE TABLE `Productos` ( `CodProdu` DOUBLE NOT NULL AUTO_INCREMENT, `DesProdu` mediumtext NOT NULL, `PreUniProdu` DECIMAL(5,2) NOT NULL DEFAULT '0.00', UNIQUE KEY `CodProdu` (`CodProdu`) ) TYPE=MyISAM AUTO_INCREMENT=1 ; # Datos Tabla Productos INSERT INTO `Productos` VALUES ('1', 'Producto1', '7.00'); INSERT INTO `Productos` VALUES ('2', 'Producto2', '100.00'); INSERT INTO `Productos` VALUES ('3', 'Producto3', '6.00'); INSERT INTO `Productos` VALUES ('4', 'Producto4', '12.50'); INSERT INTO `Productos` VALUES ('5', 'Producto5', '11.25'); INSERT INTO `Productos` VALUES ('6', 'Producto6', '30.00'); # Tabla Compras CREATE TABLE `Compras` ( `CodCompra` DOUBLE NOT NULL AUTO_INCREMENT, `CodClien` VARCHAR(8) NOT NULL DEFAULT '0', `CodProdu` DOUBLE NOT NULL DEFAULT '0', `CanComProdu` INT(11) NOT NULL DEFAULT '0', `FecCompra` DATE NOT NULL DEFAULT '0000-00-00', UNIQUE KEY `CodCompra` (`CodCompra`) ) TYPE=MyISAM AUTO_INCREMENT=1 ; # Datos Tabla Productos INSERT INTO `Compras` VALUES ('1', '00000001', '1', 10, '2004-06-20'); INSERT INTO `Compras` VALUES ('2', '00000001', '1', 30, '2004-06-20'); INSERT INTO `Compras` VALUES ('3', '00000002', '3', 5, '2004-06-20'); INSERT INTO `Compras` VALUES ('4', '00000003', '6', 100, '2004-06-20'); INSERT INTO `Compras` VALUES ('5', '00000004', '5', 5, '2004-06-20'); INSERT INTO `Compras` VALUES ('6', '00000003', '5', 2, '2004-06-20'); INSERT INTO `Compras` VALUES ('7', '00000006', '4', 1, '2004-06-20'); ##################################################################################################
Para facilitarnos la operación de crear las tablas y su data utilizaremos la base de datos test, recomiendo que graben el contenido arriba mostrado en un archivo ejemplo archivo.sql, grabamos y ejecutamos en consola.
HellFire#mysql test < archivo.sql
Aqui les dejo todo el codigo del archivo reportes.c.
/*********************************************************************************************** * gcc -I/usr/local/include/mysql -L/usr/local/lib/mysql source.c -o program -lm -lmysqlclient * * -I indica ubicacion de los header * * -L indica ubicacion de las librerias * * -o nombre del ejecutable * * -lm -l enlace al mysqlclient * ************************************************************************************************/ /*********************************************************************************************** * Autor: ACMhUnTeR <acardenas@bsdperu.org> - 2004 * ***********************************************************************************************/ #include <stdio.h> /* Manejo de datos de entrada y salida como fopen, fputs, etc */ #include <stdlib.h> /* Funciones varias como malloc, atof, etc */ #include <string.h> /* Manejo de cadenas como la funcion strcat */ #include <time.h> /* Necesaria para la captura de fecha */ #include <mysql.h> /* Necesaria para las operaciones con MySQL */ /* Estructura para manejar la api de MySQL*/ MYSQL *ConPtr,Mysql; MYSQL_RES *ResPtr; MYSQL_ROW Filas; /* Puntero que hace referencia al fichero html que usaremos para escribir el reporte */ FILE* FichHtml; /* Puntero que hace referencia al fichero log que usaremos para escribir errores en la conexion */ FILE* FichLog; /* Estructura que usaremos para capturar el tiempo local */ struct tm *TiempoPtr; time_t Tiempo; /* Arreglos donde guardaremos la fecha y nombre basado en la fecha, formateada con la funcion strftime */ char FecLocal[14]; char *NomFich; /* Arreglo que contendra la sentencia SQL que usaremos */ char Sql[500]; /* Contendra la opcion de apertura de fichero */ char *OptFich; /* Variables varias */ char NumToStr[13]; double StrToNum; double Total; /* Capturara parametros pasados por linea de comandos NroParam contendra el valor de los parametros capturados y el arreglo Parametros cada uno de los valores capturados*/ int main(int NroParam,char *Parametros[]) { /* Capturamos el fecha local,la formateamos con strftime y almacemanos en FecLocal */ Tiempo=time(NULL); TiempoPtr = localtime(&Tiempo); strftime(FecLocal, 16, "%Y-%m-%d", TiempoPtr ); switch(NroParam) { case 1: /* Concatenacion para el armado de la sentencia SQL */ /* SELECT Clientes.CodClien,Clientes.NomClien,Clientes.ApeClien,Sum(Compras.CanComProdu*Productos.PreUniProdu) as Total FROM Clientes,Compras,Productos WHERE Clientes.CodClien=Compras.CodClien AND Compras.CodProdu=Productos.CodProdu and FecCompra='AAAA-MM-DD' GROUP BY Clientes.CodClien */ strcpy(Sql,"SELECT Clientes.CodClien,Clientes.NomClien,Clientes.ApeClien,Sum(Compras.CanComProdu*Productos.PreUniProdu) as Total FROM Clientes,Compras,Productos WHERE Clientes.CodClien=Compras.CodClien AND Compras.CodProdu=Productos.CodProdu and FecCompra='"); strcat(Sql,FecLocal); strcat(Sql,"' GROUP BY Clientes.CodClien"); /* Formatea la fecha capturada por TiempoPtr y lo guarda en el arreglo NomFich */ NomFich = (char *)malloc(sizeof(char)*15); strftime(NomFich, 16, "%Y-%m-%d.html", TiempoPtr ); OptFich="a"; break; case 2: /* Concatenacion para el armado de la sentencia SQL obteniendo parametro de fecha desde linea de comando: programa */ /* SELECT Clientes.CodClien,Clientes.NomClien,Clientes.ApeClien,Sum(Compras.CanComProdu*Productos.PreUniProdu) as Total FROM Clientes,Compras,Productos WHERE Clientes.CodClien=Compras.CodClien AND Compras.CodProdu=Productos.CodProdu and FecCompra='AAAA-MM-DD' GROUP BY Clientes.CodClien */ strcpy(Sql,"SELECT Clientes.CodClien,Clientes.NomClien,Clientes.ApeClien,Sum(Compras.CanComProdu*Productos.PreUniProdu) as Total FROM Clientes,Compras,Productos WHERE Clientes.CodClien=Compras.CodClien AND Compras.CodProdu=Productos.CodProdu and FecCompra='"); strcat(Sql,Parametros[1]); strcat(Sql,"' GROUP BY Clientes.CodClien"); /* Formatea la fecha capturada por TiempoPtr y lo guarda en el arreglo NomFich */ NomFich = (char *)malloc(sizeof(char)*15); strcat(NomFich,Parametros[1]); strcat(NomFich,".html"); OptFich="w"; break; default: fprintf(stderr,"Usar: programa <fecha>\nParametro fecha en formato(AAAA-MM-DD)\n"); /* Sale del programa */ exit(1); } /* Inicializa Conexion */ mysql_init(&Mysql); /* Realiza conexion segun host,user,password,database,port,socket,id y lo asigna a ConPtr , podemos utilizar de prueba nuestro usuario root y password que le hayamos asignado */ ConPtr=mysql_real_connect(&Mysql,"localhost","MiUsuario","MiPassword","NombreDeLaDB",0,NULL,0); /* Si lanza un error la conexion lo grabamos en el archivo error.log */ if (!ConPtr) { FichLog = fopen ("error.log", "a" ); fputs("[",FichLog); fputs(FecLocal,FichLog); fputs("]",FichLog); fputs(mysql_error(&Mysql),FichLog); fputs("\n",FichLog); /* Cierra archivo error.log */ fclose(FichLog); /* Libera memoria usado con malloc */ free(NomFich); /* Sale del programa */ exit(1); } /* Abre si existe o crea si no existe el archivo y agrega al final del mismo, lo indicado por la funcion fputs */ FichHtml = fopen (NomFich, OptFich ); /* Formatea la fecha capturada por TiempoPtr y lo guarda en el arreglo FecLocal */ strftime(FecLocal, 16, "%Y-%m-%d", TiempoPtr ); fputs("<html>\n\t<title>REPORTE DE CLIENTES</title>\n\t<head>\n\t</head>\n\t<body>\n\t",FichHtml); fputs("<table width='100%'><tr><td><center><b><font size='5'><u>REPORTE DE CLIENTES</u></font></b></center></td>",FichHtml); fputs("<tr><td colspan='2'><center><b>MONTO TOTAL DE COMPRAS DIARIAS</b></center></td></tr>",FichHtml); fputs("<tr><td><center><b>Fecha:</b>",FichHtml); fputs(FecLocal,FichHtml); fputs("</center></td></tr></table><br>",FichHtml); fputs("<table width='100%' border='1'><tr><td><center><b>CODIGO</b></center></td><td><center><b>NOMBRES</b></center></td><td><center><b>APELLIDOS</b></center></td><td><center><b>MONTO</b></center></td></tr>",FichHtml); /* Realiza un query hacia la conexion ConPtr */ mysql_query(ConPtr,Sql); /* EL resultado del query es almacenado en ResPtr */ ResPtr = mysql_store_result(ConPtr); /* Recorre el arreglo obtenido por ResPtr segun el numero de filas que contenga y lo guarda en el archivo html fijarnos en lo valores del arreglo Filas[] */ while((Filas = mysql_fetch_row(ResPtr))) { fputs("<tr><td align='right'>",FichHtml); fputs(Filas[0],FichHtml); /* Filas[0] -> Clientes.CodClien */ fputs("</td><td align='right'>",FichHtml); fputs(Filas[1],FichHtml); /* Filas[1] -> Clientes.NomClien */ fputs("</td><td align='right'>",FichHtml); fputs(Filas[2],FichHtml); /* Filas[2] -> Clientes.ApeClien */ fputs("</td><td align='right'>",FichHtml); fputs(Filas[3],FichHtml); /* Filas[3] -> Sum(Compras.CanComProdu*Productos.PreUniProdu) */ fputs("</td></tr>",FichHtml); /* Convierte cadena de Filas[3] a double */ StrToNum = atof(Filas[3]); Total = Total + StrToNum; } fputs("</table></body>\n</html>",FichHtml); /* Variable que comprueba si existio un resultado en el query */ if(mysql_num_rows(ResPtr)==0) { fputs("<br><center><b>Compras no encontradas</b></center>",FichHtml); } else { /* Arma la tabla de RESUMEN */ fputs("<br><table border='1'><tr><td colspan='3'><center><b>RESUMEN</b></center></td></tr>",FichHtml); fputs("<tr><td>Total Clientes</td><td>:</td><td>",FichHtml); /* Convierte resultado entero de mysql_num_rows a caracter */ sprintf(NumToStr,"%d",mysql_num_rows(ResPtr)); fputs(NumToStr,FichHtml); fputs("</td></tr>",FichHtml); fputs("<tr><td>Total Monto</td><td>:</td><td>",FichHtml); /* Convierte resultado double entero de la variable Total con dos digitos decimales a caracter */ sprintf(NumToStr,"%.2f",Total); fputs(NumToStr,FichHtml); fputs("</td></tr></table>",FichHtml); } /* Cierra el archivo html generado*/ fclose (FichHtml); /* Libera el resultado de memoria */ mysql_free_result(ResPtr); /* Cierra la conexion */ mysql_close(ConPtr); /* Libera memoria usado con malloc*/ free(NomFich); } /* Final de Archivo */
Como se habran fijado en la cabecera del codigo del programa reporte.c, especifique el comando con el cual procedemos a compilar nuestro programa, fijarnos en nuestro sistema la ruta de las cabeceras de MySQL, de sus librerias y reemplazarlo en el comando.
HellFire# gcc -I/usr/local/include/mysql -L/usr/local/lib/mysql reporte.c -o reporte -lm -lmysqlclient
Una vez compilado podemos ejecutar de dos formas el programa pasandole parametro de fecha o no
HellFire#./reporte HellFire#./reporte 2004-06-21
El primero genera un reporte tomando la fecha del sistema y el segundo tomara por fecha el parametro pasado en formato AAAA-MM-DD.
Espero que les ayude mucho este documento para los interesados en iniciar a programar aplicaciones utilizando la API en C de MySQL, no toque todas las funciones que podemos utilizar sino hubiera sido demasiado largo el documento, como se habran fijado es muy sencillo el uso de la API y podemos combinarlo con alguna aplicacion grafica usando QT o GTK por ejemplo, eso ya queda a nuestra decision y nuestra imaginación de que aplicación desarrollar ;). Pueden encontrar el documento de referencia en el siguiente enlace http://dev.mysql.com/doc/mysql/en/Clients.html, donde veremos funciones para capturar información del sistema, realizar transacciones (MySQL >= 4.1.x), crear una base de datos, capturar nombre de campos de las tablas en fin. Saludos a la gente de eldemonio y del Grupo de Usuarios *BSD Perú :), cualquier comentario, sugerencia o duda son bienvenidos.