다음은 Ethernet MAC address 문자열을 unit64 로 변환해 주는 MySQL 용 UDF (user-defined function) 이다. MySQL 에서 UDF 작성의 좋은 예가 될것으로 판단되어 올려 둔다.
/* ** $Id: udf_eth.cc,v 1.0 2003/09/25 16:27:33 tkubinski Stable $ */
/* ** UDF eth_aton, eth_ntoa for MySQL server */
/* ** int eth_aton(char*) ** ** Converts MAC Address (string) to unsigned long long representation. ** Accepted MAC formats: ** ** a1b2c3d4e5f6 ** a1b2.c3d4.e5f6 ** a1:b2:c3:d4:e5:f6 ** ** Letter can be small or capital. ** ** ** char* eth_ntoa(unsigned long long) ** ** Converts unsigned long long to string representation. ** MAC Address is presented in a1:b2:c3:d4:e5:f6 format. ** ** ** A dynamicly loadable file should be compiled sharable ** (like: gcc -I /usr/include/mysql -shared -o udf_eth.so udf_eth.cc). */
/* ** Author: Tomasz Kubinski <tomasz@kubinski.info> 2003-08-20 ** ** Copyright (c)2003 by Tomasz Kubinski. All rights reserved. */
/* ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* ** Changelog: ** ** $Log: udf_eth.cc,v $ ** Revision 1.0 2003/09/25 16:27:33 tkubinski ** Initial revision ** */
#ifdef STANDARD #include <stdio.h> #include <string.h> #else #include <my_global.h> #include <my_sys.h> #endif
#include <mysql.h> #include <m_ctype.h> #include <m_string.h> /* To get strmov() */
#include <sys/types.h> #include <netinet/ether.h>
#ifdef HAVE_DLOPEN
/* These must be right or mysqld will not find the symbol! */
extern "C" { my_ulonglong eth_aton( UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error ); my_bool eth_aton_init( UDF_INIT *initid, UDF_ARGS *args, char *message ); void eth_aton_deinit( UDF_INIT *initid );
char *eth_ntoa( UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *length, char *null_value, char *error ); my_bool eth_ntoa_init( UDF_INIT *initid, UDF_ARGS *args, char *message ); void eth_ntoa_deinit( UDF_INIT *initid ); }
/* * Fastest way to check and convert hex digit to decimal */ const int8_t hex2dec[256] = { /* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f */ /* 00 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 10 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 20 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 30 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /* 40 */ -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 50 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 60 */ -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 70 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 80 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 90 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* a0 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* b0 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* c0 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* d0 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* e0 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* f0 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
my_ulonglong eth_aton( UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error ) { my_ulonglong n = (my_ulonglong)0; int8_t i, j, c;
if ( args->args[0] == NULL || args->lengths[0] < 12 || args->lengths[0] > 17 ) { *is_null = 1; *error = 1; return 0; }
for ( i = j = 0; i < args->lengths[0]; i++ ) { c = hex2dec[ (u_int8_t)args->args[0][i] ]; if ( c >= 0 ) { n = ( n << 4 ) + (my_ulonglong)c; j++; } }
if ( j != ETH_ALEN * 2 ) { strcpy( error, "Incorrect macaddr format" ); *is_null = 1; *error = 1; return 0; }
*is_null = 0; *error = 0; return n; }
my_bool eth_aton_init( UDF_INIT *initid, UDF_ARGS *args, char *message ) { if ( args->arg_count != 1 || args->arg_type[0] != STRING_RESULT ) { strcpy( message, "Usage: eth_aton(\"macaddr\"), where macaddr = xxxxxxxxxxxx or xx:xx:xx:xx:xx:xx or xxxx.xxxx.xxxx" ); return 1; }
initid->maybe_null = 0; return 0; }
void eth_aton_deinit( UDF_INIT *initid ) { }
char *eth_ntoa( UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *reslen, char *is_null, char *error ) { my_ulonglong n;
if ( args->args[0] == NULL ) { *is_null = 0; *error = 0; return 0; }
n = *((my_ulonglong *)args->args[0]);
sprintf( result, "%02x:%02x:%02x:%02x:%02x:%02x", (u_int8_t)( n >> 40 ), (u_int8_t)( n >> 32 ), (u_int8_t)( n >> 24 ), (u_int8_t)( n >> 16 ), (u_int8_t)( n >> 8 ), (u_int8_t)n );
*reslen = 17; *is_null = 0; *error = 0; return result; }
my_bool eth_ntoa_init( UDF_INIT *initid, UDF_ARGS *args, char *message ) { if ( args->arg_count != 1 || args->arg_type[0] != INT_RESULT ) { strcpy( message, "Usage: eth_ntoa(1234567890)" ); return 1; }
initid->maybe_null = 0; initid->max_length = 17+1; return 0; }
void eth_ntoa_deinit( UDF_INIT *initid ) { }
#endif /* HAVE_DLOPEN */ |