sq_mysql.cpp 29 KB

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