sq_mysql.cpp 29 KB

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