Thứ Ba, 26 tháng 10, 2010

Tự viết function cho mysql sử dụng Ansi C

Khi các hàm được cung cấp sắn của mysql là không đủ dùng .

Chúng ta nghĩ đến việc viết function hoặc procedure .

Nếu việc viết procedure hướng đến việc sử lý dữ liệu nội tại của database .

Thì việc viết function lại hướng đến các tiện ích làm việc trên các kiểu dữ liệu cơ bản của mysql .

Trong bài viết này mình sẽ hướng dẫn viết function ( để extends mysql ) .

1.Chuẩn bị thư viện.

sudo apt-get install libmysql++-dev

2.Dùng một Editor để soạn file C

include header :

#include <mysql/mysql.h>

Viết hàm init

int hamming_dist_init(UDF_INIT *initid, UDF_ARGS *args,
char *message)

Trong ví dụ này mình viết hàm hamming_dist nên hàm init cho nó sẽ là hamming_dist_init .

Hàm này sẽ được gọi ngay khi hàm chính được gọi . Thường việc tiền sử lý sẽ được viết ở đây ( ví dụ như việc check param).

int hamming_dist_init(UDF_INIT *initid, UDF_ARGS *args,
char *message)
{
if (args->arg_count != 2)
{
strcpy(message,"hamming_dist() requires two arguments");
return 1;
}
return 0;
}

Kiểm tra xem số tham số có =2 hay không . Nếu khác 2 thì thôgn báo lỗi và kết thúc hàm .

Viết hàm chính

Hàm chính có mẫu như sau :

long long hamming_dist(UDF_INIT *initid, UDF_ARGS *args,char *is_null, char *error)

Đây là mẫ hàm trả về kiểu long64 nếu định trả về String , mẫu sẽ khác . Hay muốn viết các hàm Aggregate sẽ dùng mẫu này :

void xxx_reset(UDF_INIT *initid, UDF_ARGS *args,
char *is_null, char *error);


Đầy đủ hàm mình đang viết :
long long hamming_dist(UDF_INIT *initid, UDF_ARGS *args,char *is_null, char *error)
{


uint64_t a1 = *((uint64_t*) args->args[0]);
uint64_t a2 = *((uint64_t*) args->args[1]);


uint32_t v1 = a1^a2;
uint32_t v2 = (a1^a2)>>32;

v1 = v1 - ((v1>>1) & 0x55555555);
v2 = v2 - ((v2>>1) & 0x55555555);
v1 = (v1 & 0x33333333) + ((v1>>2) & 0x33333333);
v2 = (v2 & 0x33333333) + ((v2>>2) & 0x33333333);
int c1 = (((v1 + (v1>>4)) & 0xF0F0F0F) * 0x1010101) >> 24;
int c2 = (((v2 + (v2>>4)) & 0xF0F0F0F) * 0x1010101) >> 24;

return c1+c2;
}

Mình thực hiện một số tính toán rồi trả về kiểu long long (64 bit)

Các bạn có thể viết hàm đơn giản như hàm add
long long add(UDF_INIT *initid, UDF_ARGS *args,char *is_null, char *error)

{

long a = *((long*) args->args[0]);

long b = *((long*) args->args[0]);

return a+b;

}

Nhìn qua 2 hàm trên các bạn có thể hiểu cách lấy tham số .(args <-- nó đấy ).

3.Compile :

gcc -shared -o hamming.so -std=c99 $(mysql_config --cflags) hamming_dist.c  $(mysql_config --libs)

Nhớ sửa tên source file và output file nhé  ( xem lại bài trước về các compile http://i-php.net/2010/10/ket-noi-den-csdl-mysql-su-dung/ )

4.Triển khai .

copy file hamming.so vừa tạo ra được vào thu mục plugin của mysql .
sudo cp hamming.so  /usr/lib/mysql/plugin/

Trên các OS khác thì thư mục này sẽ khác nhau , và cái này có thể config được trong file my.conf ( hoặc mysql.ini )

Thực hiện lệnh tạo function trong mysql
CREATE FUNCTION hamming_dist  RETURNS INT SONAME 'hamming.so';

5.Kiểm tra select hamming_dist(1121234123123,131231313131234);

Chúc các bạn thành công .

3 nhận xét:

  1. Gap loi nay :
    Can't open shared library

    Sua the' nay :
    Just an update to say that after reboot, mysql can no longer access the function. I did have to update the apparmor profile /etc/apparmor.d/usr.sbin.mysqld and add this line:

    /usr/lib/mysql/plugin/* rm,

    and restart apparmor.

    Trả lờiXóa
  2. Trên centos có thể phát sinh một số vấn đề :

    1. Không compile được do centos sử dụng lib64
    solution : thêm tham số : -fPIC vào lệnh gcc
    2. Không tìm thấy thư mục plugin của mysql
    để tìm thư mục plugindir của mysql :
    truy vấn : show variables like 'plugin_dir';

    Nếu ra giá trị rỗng thì phải config trong my.conf :
    plugin_dir=//usr/lib/mysql/plugin/

    3. Mysql không thể truy cập file .so khi create function . (Trên SeLinux nó giới hạn) :

    chcon -t texrel_shlib_t /usr/lib/mysql/plugin/hamming.so

    Trả lờiXóa
  3. Lệnh này cho phép apache connect ra các port khác 80 và 443 dùng khi muốn kết nối mysql hay memcached :( .

    Chuối thế :
    setenforce 0

    Trả lờiXóa