#include "api.h" #include "buffer.h" #include "my_global.h" #include "mysql.h" #include #include #define MY_TYPE 'MY' #pragma warning(disable: 4244) ///////////////////////////////////////////////////////////////////// class mySQL { public: mySQL() : res(0), mysql(0) { } ~mySQL() { if (mysql) mysql_close(mysql); if(res) mysql_free_result(res); } MYSQL *mysql; MYSQL_RES *res; }; void my_destroy(void* ptr) { delete (mySQL*)ptr; ptr = 0; } ///////////////////////////////////////////////////////////////////// void* my_create(void *ctx, int nargs, void** args) { mySQL *o = new mySQL; o->mysql = mysql_init(0); if (!o->mysql) api_runtime_error(ctx, "failed to initialize MySQL client"); return api_create_user(ctx, o, 0, my_destroy, MY_TYPE); } void* my_version(void *ctx, int nargs, void** args) { if (nargs < 1) api_input_error(ctx); mySQL *o = (mySQL*)api_get_user(ctx, args[0], MY_TYPE); return api_create_string(ctx, mysql_get_client_info()); } void* my_conn(void *ctx, int nargs, void** args) { if (nargs < 4) api_input_error(ctx); mySQL *o = (mySQL*)api_get_user(ctx, args[0], MY_TYPE); const char *dbname = 0; if (nargs > 4) dbname = api_get_string(ctx, args[4]); if (!mysql_real_connect( o->mysql, api_get_string(ctx, args[1]), // host api_get_string(ctx, args[2]), // user api_get_string(ctx, args[3]), // password dbname, 0, 0, 0)) { return api_create_string(ctx, mysql_error(o->mysql)); } return 0; } void* my_query(void *ctx, int nargs, void** args) { if (nargs < 2) api_input_error(ctx); mySQL *o = (mySQL*)api_get_user(ctx, args[0], MY_TYPE); if (o->res) { mysql_free_result(o->res); o->res = 0; } if (mysql_query(o->mysql, api_get_string(ctx, args[1])) == 0) { o->res = mysql_store_result(o->mysql); int rows = 0; if (o->res) rows = mysql_num_rows(o->res); return api_create_integer(ctx, rows); } return api_create_string(ctx, mysql_error(o->mysql)); } void* my_fetch(void *ctx, int nargs, void** args) { if (nargs < 1) api_input_error(ctx); mySQL *o = (mySQL*)api_get_user(ctx, args[0], MY_TYPE); if (!o->res) return 0; MYSQL_ROW row = mysql_fetch_row(o->res); if (!row) return 0; int ncol = mysql_num_fields(o->res); if (ncol > 1) { void *arr = api_create_array(ctx, ncol); for (int i = 0; i < ncol; i++) { api_set_array_object2(ctx, arr, i, row[i] ? api_create_string(0, row[i]) : api_create_string(0, "NULL")); } return arr; } else if (ncol == 1) { return api_create_string(ctx, row[0] ? row[0] : "NULL"); } return 0; } double cal2jul(const char *s) { char c[5]; strncpy(c, s, 4); c[4] = 0; int yy = atoi(c); strncpy(c, s+5, 2); c[2] = 0; int mm = atoi(c); strncpy(c, s+8, 2); int dd = atoi(c); yy -= mm < 3; mm += 12 * (mm < 3); int a = 365.25 * (yy + 4716), b = 30.6001 * (mm + 1); double d = a + b + dd - 2416556; if (strlen(s) > 18) { strncpy(c, s+11, 2); d += atof(c)/24.0; strncpy(c, s+14, 2); d += atof(c)/1440.0; strncpy(c, s+17, 2); d += atof(c)/86400.0; } return d; } void* my_data(void *ctx, int nargs, void** args) { if (nargs < 3) api_input_error(ctx); mySQL *o = (mySQL*)api_get_user(ctx, args[0], MY_TYPE); double *d = (double*)api_get_ptr(ctx, args[1]); int nd = api_get_integer(ctx, args[2]); bool flag = false; if (nargs > 3) flag = api_get_integer(ctx, args[3])!=0; if (!o->res) return api_create_integer(ctx, 0); MYSQL_ROW row = mysql_fetch_row(o->res); if (!row) return api_create_integer(ctx, 0); int ncol = mysql_num_fields(o->res); if (ncol <= 0) return api_create_integer(ctx, 0); int k = 0; while (row) { if (ncol > 1) { for (int i = 0; i < ncol; i++) { if (k >= nd) return api_create_integer(ctx, k); if (flag && i==0) { d[k++] = cal2jul(row[0]); } else { if (row[i]) d[k++] = atof(row[i]); else d[k++] = -1.e30; } } } else { if (k >= nd) return api_create_integer(ctx, k); if (flag) { d[k++] = cal2jul(row[0]); } else { if (row[0]) d[k++] = atof(row[0]); else d[k++] = -1.e30; } } row = mysql_fetch_row(o->res); } return api_create_integer(ctx, k);; } void* my_print(void *ctx, int nargs, void** args) { if (nargs < 1) api_input_error(ctx); mySQL *o = (mySQL*)api_get_user(ctx, args[0], MY_TYPE); if (!o->res) return 0; MYSQL_ROW row = mysql_fetch_row(o->res); if (!row) return 0; int ncol = mysql_num_fields(o->res); while (row) { for (int i = 0; i < ncol; i++) { if (i == ncol-1) fprintf(stdout, "%s\n", row[i] ? row[i] : "NULL"); else fprintf(stdout, "%s, ", row[i] ? row[i] : "NULL"); } row = mysql_fetch_row(o->res); } return 0; } void* my_escape(void *ctx, int nargs, void** args) { if (nargs < 2) api_input_error(ctx); mySQL *o = (mySQL*)api_get_user(ctx, args[0], MY_TYPE); if (nargs == 2) { const char *s = api_get_string(ctx, args[1]); int n = strlen(s); zsBuffer buf(2*n+2); mysql_real_escape_string(o->mysql, buf.u.pchar, s, n); return api_create_string(ctx, buf.u.pchar); } void *ptr = api_get_ptr(ctx, args[1]); int n = api_get_integer(ctx, args[2]); zsBuffer buf(2*n+2); mysql_real_escape_string(o->mysql, buf.u.pchar, (const char*)ptr, n); return api_create_string(ctx, buf.u.pchar); } ///////////////////////////////////////////////////////////////////// class zsRegPrimitive { public: zsRegPrimitive() { api_add_primitive("mysql", 0, my_create); api_add_primitive("version", MY_TYPE, my_version); api_add_primitive("connect", MY_TYPE, my_conn); api_add_primitive("query", MY_TYPE, my_query); api_add_primitive("fetch", MY_TYPE, my_fetch); api_add_primitive("data", MY_TYPE, my_data); api_add_primitive("print", MY_TYPE, my_print); api_add_primitive("escate", MY_TYPE, my_escape); } ~zsRegPrimitive() { } }; zsRegPrimitive my_register;