- Se incorporó
- 14 Enero 2008
- Mensajes
- 1.428
Estimados, en el trabajo me solicitaron que averiguara como crear extensiones custom para mysql. Después de dar vueltas por la red y jugo durante un día logre mi objetivo así que paso por acá a copy pastear el tutorial simple que hice al respecto dado que no hay mucha información en español al respecto. Se que el codigo no es de los mejores pero cumple el objetivo.
Código:
#ifdef STANDARD
/* STANDARD is defined, don't use any mysql functions */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifdef __WIN__
typedef unsigned __int64 ulonglong; /* Microsofts 64 bit types */
typedef __int64 longlong;
#else
typedef unsigned long long ulonglong;
typedef long long longlong;
#endif /*__WIN__*/
#else
#include <my_global.h>
#include <my_sys.h>
#if defined(MYSQL_SERVER)
#include <m_string.h> /* To get strmov() */
#else
/* when compiled as standalone */
#include <string.h>
#define strmov(a,b) stpcpy(a,b)
#define bzero(a,b) memset(a,0,b)
#endif
#endif
#include <mysql.h>
#include <ctype.h>
#ifdef _WIN32
/* inet_aton needs winsock library */
#pragma comment(lib, "ws2_32")
#endif
#ifdef HAVE_DLOPEN
#if !defined(HAVE_GETHOSTBYADDR_R) || !defined(HAVE_SOLARIS_STYLE_GETHOST)
static pthread_mutex_t LOCK_hostname;
#endif
//Todo lo anterior solo son las cabeceras requeridas por mysql
//se deve haber instalado las biliotecas de desarrollo de mysql y el codigo
//debe compilarse con un comando similar al siguiente
//gcc -I/usr/include/mysql -shared -fPIC -o MyTest.so test.c
//informacion recolectada de
//http://blog.loftdigital.com/blog/how-to-write-mysql-functions-in-c
//http://www.sheepsqueezers.com/joomla/media/documents/MySQLUserDefinedFunctions.pdf
//http://www.codeproject.com/Articles/15643/MySQL-User-Defined-Functions
// Mysql Provee solo un puntero para nuestros datos por lo tanto
// Usamos una estructura para almacenarlos
struct MyTest_data
{
ulonglong esnulo;
double resultado;
};
//Funcion que inicializa nuestra funcion, aca solicitamos memoria
//y realizamos los checkeos correspondientes
my_bool MyTest_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
//Creamos nuestra variable de tipo puntero para los datos
struct MyTest_data* data ;
//Revisamos el numero de argumentos
if (args->arg_count != 1)
{
strcpy(message,"MyTest() requiere al menos un argumento");
return 1;
}
//revisamos el tipo de argumento
if ((args->arg_type[0] != REAL_RESULT) )
{
strcpy(message, "Tipo incorreco: MyTest() requiere un REAL");
return 1;
}
//inicializamos la memoria necesaria
if (!(data = (struct MyTest_data*) malloc(sizeof(struct MyTest_data))))
{
strcpy(message,"No se puede inicializar la memoria para los Datos");
return 1;
}
//El resultado de nuestra funcion puede ser nulo
initid->maybe_null = 1;
//asignamos un valor inicial a nuestros datos
data->esnulo=0;
data->resultado=1.0;
//asignamos el puntero a la estructura de mysql
//Se almacena como puntero tipo char en la estructura mysql
//Por tanto debemos hacer un cast
initid->ptr = (char*)data;
return 0;
}
//Funcion de destruccion para nuestra funcion, basicamente liberamos la memoria
//solicitada en la inicializacion
void MyTest_deinit(UDF_INIT *initid)
{
//Finalizamos la memoria
free(initid->ptr);
}
//Funcion de limpieza, solo se requiere para las funciones acumulativas
//Como por ejemplo SUM, Count, etc..
//Esta función se llama cuando MySQL necesita resetear los resultados resumen.
//Se llama al comienzo de cada nuevo grupo (sentencia GROUP BY), pero también puede ser
//llamada para restablecer los valores de una consulta donde no hay registros coincidentes .
//Se Utiliza desde MYSQL 5.0 en adelante
void MyTest_clear(UDF_INIT *initid, char *is_null, char *error)
{
//casteamos el puntero char de mysql a nuestra estructura
struct MyTest_data* data = (struct MyTest_data*)initid->ptr;
//iniciamos los valores por defecto para cada grupo de datos
if (*error==1) *error=0;
data->esnulo=0;
data->resultado=1.0;
}
//Funcion de reseteo, solo se requiere para las funciones acumulativas
//Como por ejemplo SUM, Count, etc..
//Cumple la misma funcion que clear pero para Mysql 4.0
//Esta para dar retrocompatibilidad a la extension
void MyTest_reset(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error)
{
//casteamos el puntero char de mysql a nuestra estructura
struct MyTest_data* data = (struct MyTest_data*)initid->ptr;
//iniciamos los valores por defecto para cada grupo de datos
if (*error==1) *error=0;
data->esnulo=0;
data->resultado=1.0;
}
//Funcion acumulativa, solo se requiere para las funciones acumulativas
//Como por ejemplo SUM, Count, etc..
//Esta función es llamada para todas las filas que pertenecen
//al mismo grupo. Se debe utilizar para agregar el valor en el argumento UDF_ARGS
//a la variable de resumen interna.
void MyTest_add(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error)
{
//casteamos el puntero char de mysql a nuestra estructura
struct MyTest_data* data= (struct MyTest_data*)initid->ptr;
//casteamos el argumento al tipo de puntero que usamos
double* pretorno = (double*)args->args[0];
//verificamos que el puntero no sea null y asignamos los datos a nuestra variable interna
if (pretorno==NULL) *error=1;
else data->resultado=data->resultado* (*pretorno+1.0);
}
//Funcion agregada a mysql, en el caso de las funciones acumulativas debe retornar
//el valor de nuestra variable resumen interna. Para los otros casos los calculos se realizan
//en esta funcion.
double MyTest(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error)
{
//Casteamos el puntero char de mysql a nuestra estructura
struct MyTest_data* data = (struct MyTest_data*)initid->ptr;
if (*error==1)
{
//esta flag provoca que mi funcion retorne nulo independiente del valor del RETURN
*is_null = 1;
return 0.0;
}
else return (data->resultado -1.0);
}
#endif /* HAVE_DLOPEN */