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