sq_mysql.cpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823
  1. #include "squirrel.h"
  2. #include "mysql.h"
  3. #include <string.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include "sqstdblobimpl.h"
  7. #include "dynamic_library.h"
  8. /*SquiLu
  9. local mysql_functions = [
  10. ["MYSQL *", "mysql_init", "MYSQL *mysql"],
  11. ["MYSQL *", "mysql_real_connect", @"MYSQL *mysql, const char *host,
  12. const char *user,
  13. const char *passwd,
  14. const char *db,
  15. unsigned int port,
  16. const char *unix_socket,
  17. unsigned long clientflag"],
  18. ["void", "mysql_close", "MYSQL *sock"],
  19. ["const char *", "mysql_error", "MYSQL *mysql"],
  20. ["int", "mysql_ping", "MYSQL *mysql"],
  21. ["unsigned long", "mysql_real_escape_string", @"MYSQL *mysql,
  22. char *to,const char *from,
  23. unsigned long length"],
  24. ["unsigned long", "mysql_get_server_version", "MYSQL *mysql"],
  25. ["unsigned long", "mysql_insert_id", "MYSQL *mysql"],
  26. ["void", "mysql_data_seek", "MYSQL_RES *result, my_ulonglong offset"],
  27. ["MYSQL_RES *", "mysql_store_result", "MYSQL *mysql"],
  28. ["int", "mysql_real_query", @"MYSQL *mysql, const char *q,
  29. unsigned long length"],
  30. ["my_ulonglong", "mysql_num_rows", "MYSQL_RES *res"],
  31. ["my_ulonglong", "mysql_affected_rows", "MYSQL *mysql"],
  32. ["unsigned int", "mysql_num_fields", "MYSQL_RES *res"],
  33. ["MYSQL_FIELD *", "mysql_fetch_fields", "MYSQL_RES *res"],
  34. ["MYSQL_FIELD *", "mysql_fetch_field_direct", "MYSQL_RES *res, unsigned int fieldnr"],
  35. ["MYSQL_ROW", "mysql_fetch_row", "MYSQL_RES *res"],
  36. ["unsigned long *", "mysql_fetch_lengths", "MYSQL_RES *res"],
  37. ["void", "mysql_free_result", "MYSQL_RES *result"],
  38. ["my_bool", "mysql_eof", "MYSQL_RES *res"],
  39. //prepared statements
  40. ["MYSQL_STMT *", "mysql_stmt_init", "MYSQL *mysql"],
  41. ["int", "mysql_stmt_prepare", @"MYSQL_STMT *stmt, const char *query,
  42. unsigned long length"],
  43. ["int", "mysql_stmt_execute", "MYSQL_STMT *stmt"],
  44. ["unsigned long", "mysql_stmt_param_count", "MYSQL_STMT * stmt"],
  45. ["my_bool", "mysql_stmt_bind_param", "MYSQL_STMT * stmt, MYSQL_BIND * bnd"],
  46. ["my_bool", "mysql_stmt_reset", "MYSQL_STMT * stmt"],
  47. ["my_bool", "mysql_stmt_free_result", "MYSQL_STMT * stmt"],
  48. ["my_bool", "mysql_stmt_close", "MYSQL_STMT * stmt"],
  49. ["const char *", "mysql_stmt_error", "MYSQL_STMT * stmt"],
  50. ];
  51. function write_mysql_functions_declaration(){
  52. foreach(k,v in mysql_functions) {
  53. putsnl("typedef " + v[0] + " (*" + v[1] + "_t)(" + v[2] + ");");
  54. putsnl("static " + v[1] + "_t dl" + v[1] + " = 0;");
  55. }
  56. }
  57. function write_mysql_functions_load(){
  58. foreach(k,v in mysql_functions){
  59. putsnl("dl" + v[1] + " = (" + v[1] + "_t) libmysqlclient.dlsym(\"" + v[1] + "\");");
  60. putsnl("if(!dl" + v[1] + ") return false;");
  61. }
  62. }
  63. SquiLu*/
  64. static DynamicLibrary libmysqlclient;
  65. //@write_mysql_functions_declaration();
  66. // generated-code:begin
  67. typedef MYSQL * (*mysql_init_t)(MYSQL *mysql);
  68. static mysql_init_t dlmysql_init = 0;
  69. typedef MYSQL * (*mysql_real_connect_t)(MYSQL *mysql, const char *host,
  70. const char *user,
  71. const char *passwd,
  72. const char *db,
  73. unsigned int port,
  74. const char *unix_socket,
  75. unsigned long clientflag);
  76. static mysql_real_connect_t dlmysql_real_connect = 0;
  77. typedef void (*mysql_close_t)(MYSQL *sock);
  78. static mysql_close_t dlmysql_close = 0;
  79. typedef const char * (*mysql_error_t)(MYSQL *mysql);
  80. static mysql_error_t dlmysql_error = 0;
  81. typedef int (*mysql_ping_t)(MYSQL *mysql);
  82. static mysql_ping_t dlmysql_ping = 0;
  83. typedef unsigned long (*mysql_real_escape_string_t)(MYSQL *mysql,
  84. char *to,const char *from,
  85. unsigned long length);
  86. static mysql_real_escape_string_t dlmysql_real_escape_string = 0;
  87. typedef unsigned long (*mysql_get_server_version_t)(MYSQL *mysql);
  88. static mysql_get_server_version_t dlmysql_get_server_version = 0;
  89. typedef unsigned long (*mysql_insert_id_t)(MYSQL *mysql);
  90. static mysql_insert_id_t dlmysql_insert_id = 0;
  91. typedef void (*mysql_data_seek_t)(MYSQL_RES *result, my_ulonglong offset);
  92. static mysql_data_seek_t dlmysql_data_seek = 0;
  93. typedef MYSQL_RES * (*mysql_store_result_t)(MYSQL *mysql);
  94. static mysql_store_result_t dlmysql_store_result = 0;
  95. typedef int (*mysql_real_query_t)(MYSQL *mysql, const char *q,
  96. unsigned long length);
  97. static mysql_real_query_t dlmysql_real_query = 0;
  98. typedef my_ulonglong (*mysql_num_rows_t)(MYSQL_RES *res);
  99. static mysql_num_rows_t dlmysql_num_rows = 0;
  100. typedef my_ulonglong (*mysql_affected_rows_t)(MYSQL *mysql);
  101. static mysql_affected_rows_t dlmysql_affected_rows = 0;
  102. typedef unsigned int (*mysql_num_fields_t)(MYSQL_RES *res);
  103. static mysql_num_fields_t dlmysql_num_fields = 0;
  104. typedef MYSQL_FIELD * (*mysql_fetch_fields_t)(MYSQL_RES *res);
  105. static mysql_fetch_fields_t dlmysql_fetch_fields = 0;
  106. typedef MYSQL_FIELD * (*mysql_fetch_field_direct_t)(MYSQL_RES *res, unsigned int fieldnr);
  107. static mysql_fetch_field_direct_t dlmysql_fetch_field_direct = 0;
  108. typedef MYSQL_ROW (*mysql_fetch_row_t)(MYSQL_RES *res);
  109. static mysql_fetch_row_t dlmysql_fetch_row = 0;
  110. typedef unsigned long * (*mysql_fetch_lengths_t)(MYSQL_RES *res);
  111. static mysql_fetch_lengths_t dlmysql_fetch_lengths = 0;
  112. typedef void (*mysql_free_result_t)(MYSQL_RES *result);
  113. static mysql_free_result_t dlmysql_free_result = 0;
  114. typedef my_bool (*mysql_eof_t)(MYSQL_RES *res);
  115. static mysql_eof_t dlmysql_eof = 0;
  116. typedef MYSQL_STMT * (*mysql_stmt_init_t)(MYSQL *mysql);
  117. static mysql_stmt_init_t dlmysql_stmt_init = 0;
  118. typedef int (*mysql_stmt_prepare_t)(MYSQL_STMT *stmt, const char *query,
  119. unsigned long length);
  120. static mysql_stmt_prepare_t dlmysql_stmt_prepare = 0;
  121. typedef int (*mysql_stmt_execute_t)(MYSQL_STMT *stmt);
  122. static mysql_stmt_execute_t dlmysql_stmt_execute = 0;
  123. typedef unsigned long (*mysql_stmt_param_count_t)(MYSQL_STMT * stmt);
  124. static mysql_stmt_param_count_t dlmysql_stmt_param_count = 0;
  125. typedef my_bool (*mysql_stmt_bind_param_t)(MYSQL_STMT * stmt, MYSQL_BIND * bnd);
  126. static mysql_stmt_bind_param_t dlmysql_stmt_bind_param = 0;
  127. typedef my_bool (*mysql_stmt_reset_t)(MYSQL_STMT * stmt);
  128. static mysql_stmt_reset_t dlmysql_stmt_reset = 0;
  129. typedef my_bool (*mysql_stmt_free_result_t)(MYSQL_STMT * stmt);
  130. static mysql_stmt_free_result_t dlmysql_stmt_free_result = 0;
  131. typedef my_bool (*mysql_stmt_close_t)(MYSQL_STMT * stmt);
  132. static mysql_stmt_close_t dlmysql_stmt_close = 0;
  133. typedef const char * (*mysql_stmt_error_t)(MYSQL_STMT * stmt);
  134. static mysql_stmt_error_t dlmysql_stmt_error = 0;
  135. // generated-code:end
  136. #ifdef WIN32
  137. #define LIBPQ_NAME "libmysqlclient.dll"
  138. #else
  139. #define LIBPQ_NAME "libmysqlclient.so"
  140. #endif
  141. static bool load_libmysqlclient()
  142. {
  143. if(dlmysql_init) return true;
  144. if(libmysqlclient.open(LIBPQ_NAME))
  145. {
  146. //@write_mysql_functions_load();
  147. // generated-code:begin
  148. dlmysql_init = (mysql_init_t) libmysqlclient.dlsym("mysql_init");
  149. if(!dlmysql_init) return false;
  150. dlmysql_real_connect = (mysql_real_connect_t) libmysqlclient.dlsym("mysql_real_connect");
  151. if(!dlmysql_real_connect) return false;
  152. dlmysql_close = (mysql_close_t) libmysqlclient.dlsym("mysql_close");
  153. if(!dlmysql_close) return false;
  154. dlmysql_error = (mysql_error_t) libmysqlclient.dlsym("mysql_error");
  155. if(!dlmysql_error) return false;
  156. dlmysql_ping = (mysql_ping_t) libmysqlclient.dlsym("mysql_ping");
  157. if(!dlmysql_ping) return false;
  158. dlmysql_real_escape_string = (mysql_real_escape_string_t) libmysqlclient.dlsym("mysql_real_escape_string");
  159. if(!dlmysql_real_escape_string) return false;
  160. dlmysql_get_server_version = (mysql_get_server_version_t) libmysqlclient.dlsym("mysql_get_server_version");
  161. if(!dlmysql_get_server_version) return false;
  162. dlmysql_insert_id = (mysql_insert_id_t) libmysqlclient.dlsym("mysql_insert_id");
  163. if(!dlmysql_insert_id) return false;
  164. dlmysql_data_seek = (mysql_data_seek_t) libmysqlclient.dlsym("mysql_data_seek");
  165. if(!dlmysql_data_seek) return false;
  166. dlmysql_store_result = (mysql_store_result_t) libmysqlclient.dlsym("mysql_store_result");
  167. if(!dlmysql_store_result) return false;
  168. dlmysql_real_query = (mysql_real_query_t) libmysqlclient.dlsym("mysql_real_query");
  169. if(!dlmysql_real_query) return false;
  170. dlmysql_num_rows = (mysql_num_rows_t) libmysqlclient.dlsym("mysql_num_rows");
  171. if(!dlmysql_num_rows) return false;
  172. dlmysql_affected_rows = (mysql_affected_rows_t) libmysqlclient.dlsym("mysql_affected_rows");
  173. if(!dlmysql_affected_rows) return false;
  174. dlmysql_num_fields = (mysql_num_fields_t) libmysqlclient.dlsym("mysql_num_fields");
  175. if(!dlmysql_num_fields) return false;
  176. dlmysql_fetch_fields = (mysql_fetch_fields_t) libmysqlclient.dlsym("mysql_fetch_fields");
  177. if(!dlmysql_fetch_fields) return false;
  178. dlmysql_fetch_field_direct = (mysql_fetch_field_direct_t) libmysqlclient.dlsym("mysql_fetch_field_direct");
  179. if(!dlmysql_fetch_field_direct) return false;
  180. dlmysql_fetch_row = (mysql_fetch_row_t) libmysqlclient.dlsym("mysql_fetch_row");
  181. if(!dlmysql_fetch_row) return false;
  182. dlmysql_fetch_lengths = (mysql_fetch_lengths_t) libmysqlclient.dlsym("mysql_fetch_lengths");
  183. if(!dlmysql_fetch_lengths) return false;
  184. dlmysql_free_result = (mysql_free_result_t) libmysqlclient.dlsym("mysql_free_result");
  185. if(!dlmysql_free_result) return false;
  186. dlmysql_eof = (mysql_eof_t) libmysqlclient.dlsym("mysql_eof");
  187. if(!dlmysql_eof) return false;
  188. dlmysql_stmt_init = (mysql_stmt_init_t) libmysqlclient.dlsym("mysql_stmt_init");
  189. if(!dlmysql_stmt_init) return false;
  190. dlmysql_stmt_prepare = (mysql_stmt_prepare_t) libmysqlclient.dlsym("mysql_stmt_prepare");
  191. if(!dlmysql_stmt_prepare) return false;
  192. dlmysql_stmt_execute = (mysql_stmt_execute_t) libmysqlclient.dlsym("mysql_stmt_execute");
  193. if(!dlmysql_stmt_execute) return false;
  194. dlmysql_stmt_param_count = (mysql_stmt_param_count_t) libmysqlclient.dlsym("mysql_stmt_param_count");
  195. if(!dlmysql_stmt_param_count) return false;
  196. dlmysql_stmt_bind_param = (mysql_stmt_bind_param_t) libmysqlclient.dlsym("mysql_stmt_bind_param");
  197. if(!dlmysql_stmt_bind_param) return false;
  198. dlmysql_stmt_reset = (mysql_stmt_reset_t) libmysqlclient.dlsym("mysql_stmt_reset");
  199. if(!dlmysql_stmt_reset) return false;
  200. dlmysql_stmt_free_result = (mysql_stmt_free_result_t) libmysqlclient.dlsym("mysql_stmt_free_result");
  201. if(!dlmysql_stmt_free_result) return false;
  202. dlmysql_stmt_close = (mysql_stmt_close_t) libmysqlclient.dlsym("mysql_stmt_close");
  203. if(!dlmysql_stmt_close) return false;
  204. dlmysql_stmt_error = (mysql_stmt_error_t) libmysqlclient.dlsym("mysql_stmt_error");
  205. if(!dlmysql_stmt_error) return false;
  206. // generated-code:end
  207. return true;
  208. }
  209. return false;
  210. }
  211. ////////////////////////////////////////////////////////////////////////////////
  212. static const SQChar *MySQL_TAG = _SC("MySQL");
  213. static SQRESULT get_mysql_instance(HSQUIRRELVM v, SQInteger idx, MYSQL **self){
  214. SQRESULT _rc_;
  215. if((_rc_ = sq_getinstanceup(v,idx,(SQUserPointer*)self,(void*)MySQL_TAG)) < 0) return _rc_;
  216. if(!*self) return sq_throwerror(v, _SC("database is closed"));
  217. return _rc_;
  218. }
  219. #define GET_mysql_INSTANCE_AT(idx) \
  220. MYSQL *self=NULL; \
  221. if((_rc_ = get_mysql_instance(v,idx,&self)) < 0) return _rc_;
  222. #define GET_mysql_INSTANCE() GET_mysql_INSTANCE_AT(1)
  223. static const SQChar *MySQL_Result_TAG = _SC("MySQL_Result");
  224. static const SQChar *_curr_row_key = _SC("_curr_row");
  225. static SQRESULT get_mysql_result_instance(HSQUIRRELVM v, SQInteger idx, MYSQL_RES **self){
  226. SQRESULT _rc_;
  227. if((_rc_ = sq_getinstanceup(v,idx,(SQUserPointer*)self,(void*)MySQL_Result_TAG)) < 0) return _rc_;
  228. if(!*self) return sq_throwerror(v, _SC("MYSQL_RES is closed"));
  229. return _rc_;
  230. }
  231. #define GET_mysql_result_INSTANCE_AT(idx) \
  232. MYSQL_RES *self=NULL; \
  233. if((_rc_ = get_mysql_result_instance(v,idx,&self)) < 0) return _rc_;
  234. #define GET_mysql_result_INSTANCE() GET_mysql_result_INSTANCE_AT(1)
  235. static SQRESULT sq_mysql_result_releasehook(SQUserPointer p, SQInteger size, HSQUIRRELVM v)
  236. {
  237. MYSQL_RES *self = ((MYSQL_RES *)p);
  238. if (self) dlmysql_free_result(self);
  239. return 0;
  240. }
  241. static SQRESULT sq_mysql_result_close(HSQUIRRELVM v){
  242. SQ_FUNC_VARS_NO_TOP(v);
  243. GET_mysql_result_INSTANCE();
  244. dlmysql_free_result(self);
  245. sq_setinstanceup(v, 1, 0); //next calls will fail with "Pgresult is closed"
  246. return 0;
  247. }
  248. static SQRESULT sq_mysql_result_col_count(HSQUIRRELVM v){
  249. SQ_FUNC_VARS_NO_TOP(v);
  250. GET_mysql_result_INSTANCE();
  251. sq_pushinteger(v, (SQInteger)dlmysql_num_fields(self));
  252. return 1;
  253. }
  254. static SQRESULT sq_mysql_result_row_count(HSQUIRRELVM v){
  255. SQ_FUNC_VARS_NO_TOP(v);
  256. GET_mysql_result_INSTANCE();
  257. sq_pushinteger(v, (SQInteger)dlmysql_num_rows(self));
  258. return 1;
  259. }
  260. static SQRESULT sq_mysql_result_col_name(HSQUIRRELVM v){
  261. SQ_FUNC_VARS_NO_TOP(v);
  262. GET_mysql_result_INSTANCE();
  263. SQ_GET_INTEGER(v, 2, col);
  264. if(col < 0 || col > dlmysql_num_fields(self)-1)
  265. return sq_throwerror(v, _SC("invalid col number (%d)"), col);
  266. MYSQL_FIELD *fields = dlmysql_fetch_fields(self);
  267. sq_pushstring(v, fields[col].name, -1);
  268. return 1;
  269. }
  270. static int get_field_idx(MYSQL_RES *self, const SQChar *name){
  271. MYSQL_FIELD *fields = dlmysql_fetch_fields(self);
  272. unsigned int count = dlmysql_num_fields(self);
  273. for(unsigned int i=0; i<count; ++i){
  274. if(scstrcmp(name, fields[i].name) == 0){
  275. return i;
  276. }
  277. }
  278. return -1;
  279. }
  280. static SQRESULT sq_mysql_result_col_index(HSQUIRRELVM v){
  281. SQ_FUNC_VARS_NO_TOP(v);
  282. GET_mysql_result_INSTANCE();
  283. SQ_GET_STRING(v, 2, name);
  284. sq_pushinteger(v, get_field_idx(self, name));
  285. return 1;
  286. }
  287. static SQRESULT sq_mysql_result_eof(HSQUIRRELVM v){
  288. SQ_FUNC_VARS_NO_TOP(v);
  289. GET_mysql_result_INSTANCE();
  290. sq_pushstring(v, _curr_row_key, -1);
  291. if(sq_get(v, 1) == SQ_OK){
  292. SQ_GET_INTEGER(v, -1, curr_row);
  293. sq_pushbool(v, curr_row < dlmysql_num_rows(self));
  294. }
  295. else sq_pushbool(v, SQTrue);
  296. return 1;
  297. }
  298. static SQRESULT sq_mysql_result_next_row(HSQUIRRELVM v){
  299. SQ_FUNC_VARS_NO_TOP(v);
  300. GET_mysql_result_INSTANCE();
  301. sq_pushstring(v, _curr_row_key, -1);
  302. sq_push(v, -1); //make a copy
  303. if(sq_get(v, 1) == SQ_OK){
  304. SQ_GET_INTEGER(v, -1, curr_row);
  305. if(++curr_row < dlmysql_num_rows(self)){
  306. sq_poptop(v);
  307. sq_pushinteger(v, curr_row);
  308. sq_set(v, 1);
  309. sq_pushbool(v, SQTrue);
  310. return 1;
  311. }
  312. }
  313. sq_pushbool(v, SQFalse);
  314. return 1;
  315. }
  316. static SQRESULT sq_mysql_result_col_value(HSQUIRRELVM v){
  317. SQ_FUNC_VARS_NO_TOP(v);
  318. GET_mysql_result_INSTANCE();
  319. SQObjectType ptype = sq_gettype(v, 2);
  320. int col = -1;
  321. if(ptype == OT_STRING){
  322. SQ_GET_STRING(v, 2, col_name);
  323. col = get_field_idx(self, col_name);
  324. }
  325. else
  326. {
  327. SQ_GET_INTEGER(v, 2, idx);
  328. col = idx;
  329. }
  330. if(col < 0) return sq_throwerror(v, _SC("invalid col index/name"));
  331. sq_pushstring(v, _curr_row_key, -1);
  332. if(sq_get(v, 1) == SQ_OK){
  333. SQ_GET_INTEGER(v, -1, curr_row);
  334. if(curr_row < dlmysql_num_rows(self)){
  335. dlmysql_data_seek(self, curr_row);
  336. const MYSQL_ROW res_row = dlmysql_fetch_row(self);
  337. unsigned long *lengths = dlmysql_fetch_lengths(self);
  338. sq_pushstring(v, (const SQChar*)res_row[col], lengths[col]);
  339. return 1;
  340. }
  341. }
  342. return SQ_ERROR;
  343. }
  344. static SQRESULT sq_mysql_result_row_as_array(HSQUIRRELVM v){
  345. SQ_FUNC_VARS(v);
  346. GET_mysql_result_INSTANCE();
  347. SQ_OPT_INTEGER(v, 2, row, -1);
  348. if(row < 0){
  349. sq_pushstring(v, _curr_row_key, -1);
  350. if(sq_get(v, 1) == SQ_OK){
  351. sq_getinteger(v, -1, &row);
  352. }
  353. }
  354. int row_count = dlmysql_num_rows(self);
  355. if(row < 0 || row >= row_count) return sq_throwerror(v, _SC("invalid row (%d)"), row);
  356. int col_count = dlmysql_num_fields(self);
  357. sq_newarray(v, col_count);
  358. dlmysql_data_seek(self, row);
  359. const MYSQL_ROW res_row = dlmysql_fetch_row(self);
  360. unsigned long *lengths = dlmysql_fetch_lengths(self);
  361. for(int i=0; i < col_count; ++i){
  362. sq_pushinteger(v, i);
  363. sq_pushstring(v, (const SQChar*)res_row[i], lengths[i]);
  364. sq_rawset(v, -3);
  365. }
  366. return 1;
  367. }
  368. #define _DECL_FUNC(name,nparams,tycheck) {_SC(#name), sq_mysql_result_##name,nparams,tycheck}
  369. static SQRegFunction sq_mysql_result_methods[] =
  370. {
  371. _DECL_FUNC(close, 1, _SC("x")),
  372. _DECL_FUNC(eof, 1, _SC("x")),
  373. _DECL_FUNC(next_row, 1, _SC("x")),
  374. _DECL_FUNC(col_count, 1, _SC("x")),
  375. _DECL_FUNC(row_count, 1, _SC("x")),
  376. _DECL_FUNC(col_name, 2, _SC("xi")),
  377. _DECL_FUNC(col_index, 2, _SC("xs")),
  378. _DECL_FUNC(col_value, 2, _SC("x i|s")),
  379. _DECL_FUNC(row_as_array, -1, _SC("xi")),
  380. {0,0}
  381. };
  382. #undef _DECL_FUNC
  383. static const SQChar *MySQL_Statement_TAG = _SC("MySQL_Statement");
  384. static SQRESULT get_mysql_statement_instance(HSQUIRRELVM v, SQInteger idx, MYSQL_STMT **self){
  385. SQRESULT _rc_;
  386. if((_rc_ = sq_getinstanceup(v,idx,(SQUserPointer*)self,(void*)MySQL_Statement_TAG)) < 0) return _rc_;
  387. if(!*self) return sq_throwerror(v, _SC("MySql statement is closed"));
  388. return _rc_;
  389. }
  390. #define GET_mysql_statement_INSTANCE_AT(idx) \
  391. MYSQL_STMT *self=NULL; \
  392. if((_rc_ = get_mysql_statement_instance(v,idx,&self)) < 0) return _rc_;
  393. #define GET_mysql_statement_INSTANCE() GET_mysql_statement_INSTANCE_AT(1)
  394. static SQRESULT sq_mysql_statement_releasehook(SQUserPointer p, SQInteger size, HSQUIRRELVM v)
  395. {
  396. MYSQL_STMT *self = ((MYSQL_STMT *)p);
  397. if (self) dlmysql_stmt_close(self);
  398. return 0;
  399. }
  400. static SQRESULT sq_mysql_statement_close(HSQUIRRELVM v){
  401. SQ_FUNC_VARS_NO_TOP(v);
  402. GET_mysql_statement_INSTANCE();
  403. sq_mysql_statement_releasehook(self, 0, v);
  404. sq_setinstanceup(v, 1, 0); //next calls will fail with "Pgstatement is closed"
  405. return 0;
  406. }
  407. class AllocMemory {
  408. unsigned int mem_size;
  409. public:
  410. unsigned char *mem;
  411. AllocMemory(unsigned int size){
  412. mem_size = size;
  413. mem = (unsigned char *)sq_malloc(mem_size);
  414. }
  415. ~AllocMemory(){
  416. if(mem) sq_free(mem, mem_size);
  417. }
  418. };
  419. static SQRESULT sq_mysql_statement_bind(HSQUIRRELVM v){
  420. SQ_FUNC_VARS(v);
  421. GET_mysql_statement_INSTANCE();
  422. unsigned long expected_params = dlmysql_stmt_param_count(self);
  423. if(_top_ != expected_params){
  424. return sq_throwerror(v, "Expect %d params but got %d !", expected_params, _top_);
  425. }
  426. unsigned int bind_memory_size = sizeof(MYSQL_BIND) * expected_params;
  427. AllocMemory bind_mem(bind_memory_size);
  428. AllocMemory buffer(expected_params * sizeof(double));
  429. if (expected_params > 0) {
  430. if (bind_mem.mem == NULL || buffer.mem == NULL) {
  431. return sq_throwerror(v, "Could not alloc bind params");
  432. }
  433. memset(bind_mem.mem, 0, bind_memory_size);
  434. }
  435. MYSQL_BIND *bind = (MYSQL_BIND*)bind_mem.mem;
  436. int offset = 0;
  437. for (int argn = 2; argn <= _top_; ++argn) {
  438. SQObjectType ptype = sq_gettype(v, argn);
  439. int i = argn - 2;
  440. const char *str = NULL;
  441. size_t *str_len = NULL;
  442. double *num = NULL;
  443. int *boolean_or_int = NULL;
  444. switch(ptype) {
  445. case OT_NULL:{
  446. bind[i].buffer_type = MYSQL_TYPE_NULL;
  447. bind[i].is_null = (my_bool*)1;
  448. }
  449. break;
  450. case OT_BOOL:{
  451. SQ_GET_BOOL(v, argn, param_bool);
  452. boolean_or_int = (int *)(buffer.mem + offset);
  453. offset += sizeof(int);
  454. *boolean_or_int = param_bool;
  455. bind[i].buffer_type = MYSQL_TYPE_LONG;
  456. bind[i].is_null = (my_bool*)0;
  457. bind[i].buffer = (char *)boolean_or_int;
  458. bind[i].length = 0;
  459. }
  460. break;
  461. case OT_INTEGER:{
  462. SQ_GET_INTEGER(v, argn, param_int);
  463. boolean_or_int = (int *)(buffer.mem + offset);
  464. offset += sizeof(int);
  465. *boolean_or_int = param_int;
  466. bind[i].buffer_type = MYSQL_TYPE_LONG;
  467. bind[i].is_null = (my_bool*)0;
  468. bind[i].buffer = (char *)boolean_or_int;
  469. bind[i].length = 0;
  470. }
  471. break;
  472. case OT_FLOAT:{
  473. /*
  474. * num needs to be it's own
  475. * memory here
  476. */
  477. num = (double *)(buffer.mem + offset);
  478. offset += sizeof(double);
  479. SQ_GET_FLOAT(v, argn, param_float);
  480. *num = param_float;
  481. bind[i].buffer_type = MYSQL_TYPE_DOUBLE;
  482. bind[i].is_null = (my_bool*)0;
  483. bind[i].buffer = (char *)num;
  484. bind[i].length = 0;
  485. }
  486. break;
  487. case OT_STRING:{
  488. SQ_GET_STRING(v, argn, param_string);
  489. str_len = (size_t *)(buffer.mem + offset);
  490. offset += sizeof(size_t);
  491. str = param_string;
  492. bind[i].buffer_type = MYSQL_TYPE_STRING;
  493. bind[i].is_null = (my_bool*)0;
  494. bind[i].buffer = (char *)str;
  495. bind[i].length = str_len;
  496. }
  497. break;
  498. default:{
  499. return sq_throwerror(v, "Unsupported bind parameter type %d", i);
  500. }
  501. }
  502. }
  503. sq_pushbool(v, dlmysql_stmt_bind_param(self, bind));
  504. return 1;
  505. }
  506. static SQRESULT sq_mysql_statement_execute(HSQUIRRELVM v){
  507. SQ_FUNC_VARS_NO_TOP(v);
  508. GET_mysql_statement_INSTANCE();
  509. if (dlmysql_stmt_execute(self)) {
  510. return sq_throwerror(v, _SC("error executing prepared statement. MySQL: %s"), dlmysql_stmt_error(self));
  511. }
  512. return 0;
  513. }
  514. #define _DECL_FUNC(name,nparams,tycheck) {_SC(#name), sq_mysql_statement_##name,nparams,tycheck}
  515. static SQRegFunction sq_mysql_statement_methods[] =
  516. {
  517. _DECL_FUNC(close, 1, _SC("x")),
  518. _DECL_FUNC(bind, -2, _SC("x.")),
  519. _DECL_FUNC(execute, 1, _SC("x")),
  520. {0,0}
  521. };
  522. #undef _DECL_FUNC
  523. static SQRESULT sq_mysql_releasehook(SQUserPointer p, SQInteger size, HSQUIRRELVM v)
  524. {
  525. MYSQL *self = ((MYSQL *)p);
  526. if (self) dlmysql_close(self);
  527. return 0;
  528. }
  529. static SQRESULT sq_mysql_constructor(HSQUIRRELVM v)
  530. {
  531. SQ_FUNC_VARS(v);
  532. SQ_GET_STRING(v, 2, host);
  533. SQ_GET_STRING(v, 3, username);
  534. SQ_GET_STRING(v, 4, password);
  535. SQ_GET_STRING(v, 5, sourcename);
  536. SQ_OPT_INTEGER(v, 6, port, 3306);
  537. MYSQL *self=0;
  538. if(load_libmysqlclient())
  539. {
  540. self = dlmysql_init(NULL);
  541. if (!self) return sq_throwerror(v, _SC("error connecting: Out of memory."));
  542. if (!dlmysql_real_connect(self, host, username, password, sourcename, port, NULL, 0))
  543. {
  544. SQRESULT res = sq_throwerror(v, _SC("error connecting to database. MySQL: %s"), dlmysql_error(self));
  545. dlmysql_close (self); /* Close conn if connect failed */
  546. return res;
  547. }
  548. }
  549. else return sq_throwerror(v, _SC("Failed to load libmysqlclient !"));
  550. sq_setinstanceup(v, 1, self);
  551. sq_setreleasehook(v,1, sq_mysql_releasehook);
  552. //save a weakref to allow statement return it's db
  553. sq_pushuserpointer(v, self);
  554. sq_weakref(v, 1);
  555. sq_setonregistrytable(v);
  556. return 1;
  557. }
  558. static SQRESULT sq_mysql_close(HSQUIRRELVM v){
  559. SQ_FUNC_VARS_NO_TOP(v);
  560. GET_mysql_INSTANCE();
  561. dlmysql_close(self);
  562. sq_setinstanceup(v, 1, 0); //next calls will fail with "database is closed"
  563. return 0;
  564. }
  565. static SQRESULT sq_mysql_exec_dml(HSQUIRRELVM v){
  566. SQ_FUNC_VARS_NO_TOP(v);
  567. GET_mysql_INSTANCE();
  568. SQ_GET_STRING(v, 2, szSQL);
  569. if (dlmysql_real_query(self, szSQL, szSQL_size))
  570. /* error executing query */
  571. return sq_throwerror(v, _SC("error executing query. MySQL: %s"), dlmysql_error(self));
  572. sq_pushinteger(v, (SQInteger)dlmysql_affected_rows(self));
  573. return 1;
  574. }
  575. static SQRESULT sq_mysql_exec_scalar(HSQUIRRELVM v){
  576. SQ_FUNC_VARS_NO_TOP(v);
  577. GET_mysql_INSTANCE();
  578. SQ_GET_STRING(v, 2, szSQL);
  579. int result = 0;
  580. if (dlmysql_real_query(self, szSQL, szSQL_size))
  581. /* error executing query */
  582. return sq_throwerror(v, _SC("error executing query. MySQL: %s"), dlmysql_error(self));
  583. MYSQL_RES *qres = dlmysql_store_result(self);
  584. bool is_ok = (dlmysql_num_rows(qres) == 1) && (dlmysql_num_fields(qres) > 0);
  585. if (is_ok) {
  586. MYSQL_ROW row = dlmysql_fetch_row(qres);
  587. unsigned long *lengths = dlmysql_fetch_lengths(qres);
  588. result = lengths[0] && row[0] ? atoi(row[0]) : 0;
  589. }
  590. dlmysql_free_result(qres);
  591. if (!is_ok) return sq_throwerror(v, _SC("invalid scalar query (%s)"), szSQL);
  592. sq_pushinteger(v, result);
  593. return 1;
  594. }
  595. static SQRESULT sq_mysql_exec_query(HSQUIRRELVM v){
  596. SQ_FUNC_VARS_NO_TOP(v);
  597. GET_mysql_INSTANCE();
  598. SQ_GET_STRING(v, 2, szSQL);
  599. if (dlmysql_real_query(self, szSQL, szSQL_size))
  600. /* error executing query */
  601. return sq_throwerror(v, _SC("error executing query. MySQL: %s"), dlmysql_error(self));
  602. MYSQL_RES *qres = dlmysql_store_result(self);
  603. sq_pushroottable(v);
  604. sq_pushstring(v, MySQL_Result_TAG, -1);
  605. if(sq_get(v, -2) == SQ_OK){
  606. if(sq_createinstance(v, -1) == SQ_OK){
  607. sq_setinstanceup(v, -1, qres);
  608. sq_setreleasehook(v, -1, sq_mysql_result_releasehook);
  609. sq_pushstring(v, _curr_row_key, -1);
  610. sq_pushinteger(v, -1);
  611. sq_set(v, -3);
  612. return 1;
  613. }
  614. }
  615. return SQ_ERROR;
  616. }
  617. static SQRESULT sq_mysql_prepare(HSQUIRRELVM v){
  618. SQ_FUNC_VARS_NO_TOP(v);
  619. GET_mysql_INSTANCE();
  620. SQ_GET_STRING(v, 2, szSQL);
  621. MYSQL_STMT *stmt = dlmysql_stmt_init(self);
  622. if (!stmt) return sq_throwerror(v, _SC(" mysql_stmt_init(), out of memory\n"));
  623. if (dlmysql_stmt_prepare(stmt, szSQL, szSQL_size)) {
  624. SQRESULT res = sq_throwerror(v, dlmysql_stmt_error(stmt));
  625. dlmysql_stmt_close(stmt);
  626. return res;
  627. }
  628. sq_pushroottable(v);
  629. sq_pushstring(v, MySQL_Statement_TAG, -1);
  630. if(sq_get(v, -2) == SQ_OK){
  631. if(sq_createinstance(v, -1) == SQ_OK){
  632. sq_setinstanceup(v, -1, stmt);
  633. sq_setreleasehook(v, -1, sq_mysql_statement_releasehook);
  634. return 1;
  635. }
  636. }
  637. return SQ_ERROR;
  638. }
  639. static SQRESULT sq_mysql_error_message(HSQUIRRELVM v){
  640. SQ_FUNC_VARS_NO_TOP(v);
  641. GET_mysql_INSTANCE();
  642. sq_pushstring(v, dlmysql_error(self), -1);
  643. return 1;
  644. }
  645. static SQRESULT sq_mysql_version(HSQUIRRELVM v){
  646. SQ_FUNC_VARS_NO_TOP(v);
  647. GET_mysql_INSTANCE();
  648. sq_pushinteger(v, (SQInteger)dlmysql_get_server_version(self));
  649. return 1;
  650. }
  651. static SQRESULT sq_mysql_last_insert_id(HSQUIRRELVM v){
  652. SQ_FUNC_VARS_NO_TOP(v);
  653. GET_mysql_INSTANCE();
  654. sq_pushinteger(v, (SQInteger)dlmysql_insert_id(self));
  655. return 1;
  656. }
  657. static SQRESULT sq_mysql_ping(HSQUIRRELVM v){
  658. SQ_FUNC_VARS_NO_TOP(v);
  659. GET_mysql_INSTANCE();
  660. sq_pushinteger(v, (SQInteger)dlmysql_ping(self));
  661. return 1;
  662. }
  663. static SQRESULT sq_mysql_escape_string(HSQUIRRELVM v){
  664. SQ_FUNC_VARS_NO_TOP(v);
  665. GET_mysql_INSTANCE();
  666. SQ_GET_STRING(v, 2, str);
  667. SQInteger to_size = (str_size+1) * sizeof(SQChar);
  668. SQChar *to = sq_getscratchpad(v, to_size);
  669. if(to) {
  670. SQInteger new_size = (SQInteger)dlmysql_real_escape_string(self, to, str, str_size);
  671. sq_pushstring(v, to, new_size);
  672. return 1;
  673. }
  674. return sq_throwerror(v, _SC("could not allocate escaped string"));
  675. }
  676. #define _DECL_FUNC(name,nparams,tycheck) {_SC(#name), sq_mysql_##name,nparams,tycheck}
  677. static SQRegFunction sq_mysql_methods[] =
  678. {
  679. _DECL_FUNC(constructor, -5, _SC("xssssi")),
  680. _DECL_FUNC(close, 1, _SC("x")),
  681. _DECL_FUNC(ping, 1, _SC("x")),
  682. _DECL_FUNC(exec_dml, 2, _SC("xs")),
  683. _DECL_FUNC(exec_scalar, 2, _SC("xs")),
  684. _DECL_FUNC(exec_query, 2, _SC("xs")),
  685. _DECL_FUNC(prepare, 2, _SC("xs")),
  686. _DECL_FUNC(error_message, 1, _SC("x")),
  687. _DECL_FUNC(version, 1, _SC("x")),
  688. _DECL_FUNC(last_insert_id, 1, _SC("x")),
  689. _DECL_FUNC(escape_string, 1, _SC("xs")),
  690. {0,0}
  691. };
  692. #undef _DECL_FUNC
  693. #ifdef __cplusplus
  694. extern "C" {
  695. #endif
  696. SQRESULT sqext_register_MySQL(HSQUIRRELVM v)
  697. {
  698. sq_pushstring(v,MySQL_TAG,-1);
  699. sq_newclass(v,SQFalse);
  700. sq_settypetag(v,-1,(void*)MySQL_TAG);
  701. sq_insert_reg_funcs(v, sq_mysql_methods);
  702. sq_newslot(v,-3,SQTrue);
  703. sq_pushstring(v,MySQL_Statement_TAG,-1);
  704. sq_newclass(v,SQFalse);
  705. sq_settypetag(v,-1,(void*)MySQL_Statement_TAG);
  706. sq_insert_reg_funcs(v, sq_mysql_statement_methods);
  707. sq_newslot(v,-3,SQTrue);
  708. sq_pushstring(v,MySQL_Result_TAG,-1);
  709. sq_newclass(v,SQFalse);
  710. sq_settypetag(v,-1,(void*)MySQL_Result_TAG);
  711. sq_insert_reg_funcs(v, sq_mysql_result_methods);
  712. sq_pushstring(v, _curr_row_key, -1);
  713. sq_pushnull(v);
  714. sq_newslot(v, -3, SQFalse);
  715. sq_newslot(v,-3,SQTrue);
  716. return 0;
  717. }
  718. #ifdef __cplusplus
  719. }
  720. #endif