mysql.c 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  1. /*
  2. * Copyright (C)2005-2018 Haxe Foundation
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a
  5. * copy of this software and associated documentation files (the "Software"),
  6. * to deal in the Software without restriction, including without limitation
  7. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8. * and/or sell copies of the Software, and to permit persons to whom the
  9. * Software is furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  20. * DEALINGS IN THE SOFTWARE.
  21. */
  22. #define HL_NAME(n) mysql_ ## n
  23. #include <hl.h>
  24. #include <stdlib.h>
  25. #include <stdio.h>
  26. #include <time.h>
  27. #include "mysql.h"
  28. #include <string.h>
  29. HL_PRIM void error( MYSQL *m, const char *msg ) {
  30. hl_buffer *b = hl_alloc_buffer();
  31. hl_buffer_cstr(b,msg);
  32. hl_buffer_cstr(b," ");
  33. hl_buffer_cstr(b,mysql_error(m));
  34. hl_throw_buffer(b);
  35. }
  36. // ---------------------------------------------------------------
  37. // Result
  38. #undef CONV_FLOAT
  39. typedef enum {
  40. CONV_INT,
  41. CONV_STRING,
  42. CONV_FLOAT,
  43. CONV_BINARY,
  44. CONV_DATE,
  45. CONV_DATETIME,
  46. CONV_JSON,
  47. CONV_BOOL
  48. } CONV;
  49. typedef struct {
  50. void *free;
  51. MYSQL_RES *r;
  52. int nfields;
  53. CONV *fields_convs;
  54. int *fields_ids;
  55. MYSQL_ROW current;
  56. } result;
  57. typedef struct {
  58. void *free;
  59. MYSQL *c;
  60. } connection;
  61. static vclosure *conv_string = NULL;
  62. static vclosure *conv_json = NULL;
  63. static vclosure *conv_bytes = NULL;
  64. static vclosure *conv_date = NULL;
  65. static void free_result( result *r ) {
  66. mysql_free_result(r->r);
  67. free(r->fields_ids);
  68. free(r->fields_convs);
  69. }
  70. HL_PRIM int HL_NAME(result_get_length)( result *r ) {
  71. if( r->r == NULL )
  72. return r->nfields;
  73. return (int)mysql_num_rows(r->r);
  74. }
  75. HL_PRIM int HL_NAME(result_get_nfields)( result *r ) {
  76. return r->nfields;
  77. }
  78. HL_PRIM varray *HL_NAME(result_get_fields_names)( result *r ) {
  79. int k;
  80. MYSQL_FIELD *fields = mysql_fetch_fields(r->r);
  81. varray *a = hl_alloc_array(&hlt_bytes,r->nfields);
  82. for(k=0;k<r->nfields;k++)
  83. hl_aptr(a,vbyte*)[k] = (vbyte*)fields[k].name;
  84. return a;
  85. }
  86. HL_PRIM vdynamic *HL_NAME(result_next)( result *r ) {
  87. unsigned long *lengths = NULL;
  88. MYSQL_ROW row = mysql_fetch_row(r->r);
  89. if( row == NULL )
  90. return NULL;
  91. int i;
  92. struct tm t;
  93. vdynamic *obj = (vdynamic*)hl_alloc_dynobj();
  94. vdynamic arg;
  95. vdynamic length;
  96. vdynamic *pargs[2];
  97. pargs[0] = &arg;
  98. pargs[1] = &length;
  99. length.t = &hlt_i32;
  100. r->current = row;
  101. for(i=0;i<r->nfields;i++) {
  102. if( row[i] == NULL ) continue;
  103. vdynamic *value = NULL;
  104. switch( r->fields_convs[i] ) {
  105. case CONV_INT:
  106. hl_dyn_seti(obj, r->fields_ids[i], &hlt_i32, atoi(row[i]));
  107. break;
  108. case CONV_STRING:
  109. arg.t = &hlt_bytes;
  110. arg.v.ptr = row[i];
  111. value = hl_dyn_call(conv_string, pargs, 1);
  112. break;
  113. case CONV_JSON:
  114. arg.t = &hlt_bytes;
  115. arg.v.ptr = row[i];
  116. value = hl_dyn_call(conv_json, pargs, 1);
  117. break;
  118. case CONV_BOOL:
  119. hl_dyn_seti(obj, r->fields_ids[i], &hlt_bool, (int)(*row[i] != '0'));
  120. break;
  121. case CONV_FLOAT:
  122. hl_dyn_setd(obj, r->fields_ids[i], atof(row[i]));
  123. break;
  124. case CONV_BINARY:
  125. if( lengths == NULL ) {
  126. lengths = mysql_fetch_lengths(r->r);
  127. if( lengths == NULL ) hl_error("mysql_fetch_lengths");
  128. }
  129. arg.t = &hlt_bytes;
  130. arg.v.ptr = row[i];
  131. length.v.i = lengths[i];
  132. value = hl_dyn_call(conv_bytes, pargs, 2);
  133. break;
  134. case CONV_DATE:
  135. sscanf(row[i],"%4d-%2d-%2d",&t.tm_year,&t.tm_mon,&t.tm_mday);
  136. t.tm_hour = 0;
  137. t.tm_min = 0;
  138. t.tm_sec = 0;
  139. t.tm_isdst = -1;
  140. t.tm_year -= 1900;
  141. t.tm_mon--;
  142. arg.t = &hlt_i32;
  143. arg.v.i = (int)mktime(&t);
  144. value = hl_dyn_call(conv_date,pargs, 1);
  145. break;
  146. case CONV_DATETIME:
  147. sscanf(row[i],"%4d-%2d-%2d %2d:%2d:%2d",&t.tm_year,&t.tm_mon,&t.tm_mday,&t.tm_hour,&t.tm_min,&t.tm_sec);
  148. t.tm_isdst = -1;
  149. t.tm_year -= 1900;
  150. t.tm_mon--;
  151. arg.t = &hlt_i32;
  152. arg.v.i = (int)mktime(&t);
  153. value = hl_dyn_call(conv_date,pargs, 1);
  154. break;
  155. default:
  156. break;
  157. }
  158. if( value ) hl_dyn_setp(obj, r->fields_ids[i], &hlt_dyn, value);
  159. }
  160. return obj;
  161. }
  162. HL_PRIM vbyte *HL_NAME(result_get)( result *r, int n ) {
  163. const char *str;
  164. if( n < 0 || n >= r->nfields )
  165. return NULL;
  166. if( !r->current ) {
  167. HL_NAME(result_next)(r);
  168. if( !r->current )
  169. return NULL;
  170. }
  171. str = r->current[n];
  172. return (vbyte*)(str ? str : "");
  173. }
  174. HL_PRIM int HL_NAME(result_get_int)( result *r, int n ) {
  175. const char *str;
  176. if( n < 0 || n >= r->nfields )
  177. return 0;
  178. if( !r->current ) {
  179. HL_NAME(result_next)(r);
  180. if( !r->current )
  181. return 0;
  182. }
  183. str = r->current[n];
  184. return str ? atoi(str) : 0;
  185. }
  186. HL_PRIM double HL_NAME(result_get_float)( result *r, int n ) {
  187. const char *str;
  188. if( n < 0 || n >= r->nfields )
  189. return 0.;
  190. if( !r->current ) {
  191. HL_NAME(result_next)(r);
  192. if( !r->current )
  193. return 0.;
  194. }
  195. str = r->current[n];
  196. return str ? atof(str) : 0.;
  197. }
  198. static CONV convert_type( enum enum_field_types t, int flags, unsigned int length ) {
  199. // FIELD_TYPE_TIME
  200. // FIELD_TYPE_YEAR
  201. // FIELD_TYPE_NEWDATE
  202. // FIELD_TYPE_NEWDATE + 2: // 5.0 MYSQL_TYPE_BIT
  203. switch( t ) {
  204. case FIELD_TYPE_TINY:
  205. if( length == 1 )
  206. return CONV_BOOL;
  207. case FIELD_TYPE_SHORT:
  208. case FIELD_TYPE_LONG:
  209. case FIELD_TYPE_INT24:
  210. return CONV_INT;
  211. case FIELD_TYPE_LONGLONG:
  212. case FIELD_TYPE_DECIMAL:
  213. case FIELD_TYPE_FLOAT:
  214. case FIELD_TYPE_DOUBLE:
  215. case 246: // 5.0 MYSQL_NEW_DECIMAL
  216. return CONV_FLOAT;
  217. case 245: // JSON
  218. return CONV_JSON;
  219. case FIELD_TYPE_BLOB:
  220. case FIELD_TYPE_TINY_BLOB:
  221. case FIELD_TYPE_MEDIUM_BLOB:
  222. case FIELD_TYPE_LONG_BLOB:
  223. if( (flags & BINARY_FLAG) != 0 )
  224. return CONV_BINARY;
  225. return CONV_STRING;
  226. case FIELD_TYPE_DATETIME:
  227. case FIELD_TYPE_TIMESTAMP:
  228. return CONV_DATETIME;
  229. case FIELD_TYPE_DATE:
  230. return CONV_DATE;
  231. case FIELD_TYPE_NULL:
  232. case FIELD_TYPE_ENUM:
  233. case FIELD_TYPE_SET:
  234. //case FIELD_TYPE_VAR_STRING:
  235. //case FIELD_TYPE_GEOMETRY:
  236. // 5.0 MYSQL_TYPE_VARCHAR
  237. default:
  238. if( (flags & BINARY_FLAG) != 0 )
  239. return CONV_BINARY;
  240. return CONV_STRING;
  241. }
  242. }
  243. static result *alloc_result( connection *c, MYSQL_RES *r ) {
  244. result *res = (result*)hl_gc_alloc_finalizer(sizeof(result));
  245. int num_fields = mysql_num_fields(r);
  246. int i;
  247. MYSQL_FIELD *fields = mysql_fetch_fields(r);
  248. res->free = free_result;
  249. res->r = r;
  250. res->current = NULL;
  251. res->nfields = num_fields;
  252. res->fields_ids = (int*)malloc(sizeof(int)*num_fields);
  253. res->fields_convs = (CONV*)malloc(sizeof(CONV)*num_fields);
  254. for(i=0;i<num_fields;i++) {
  255. int id;
  256. if( strchr(fields[i].name,'(') )
  257. id = hl_hash_gen(USTR("???"),true); // looks like an inner request : prevent hashing + cashing it
  258. else
  259. id = hl_hash_gen(hl_to_utf16(fields[i].name),true);
  260. res->fields_ids[i] = id;
  261. res->fields_convs[i] = convert_type(fields[i].type,fields[i].flags,fields[i].length);
  262. }
  263. return res;
  264. }
  265. // ---------------------------------------------------------------
  266. // Connection
  267. HL_PRIM void HL_NAME(close_wrap)( connection *c ) {
  268. if( c->c ) {
  269. mp_close(c->c);
  270. c->c = NULL;
  271. }
  272. }
  273. HL_PRIM bool HL_NAME(select_db_wrap)( connection *c, const char *db ) {
  274. return mysql_select_db(c->c,db) == 0;
  275. }
  276. HL_PRIM result *HL_NAME(request)( connection *c, const char *rq, int rqLen ) {
  277. if( mysql_real_query(c->c,rq,rqLen) != 0 )
  278. error(c->c,rq);
  279. MYSQL_RES *res = mysql_store_result(c->c);
  280. if( res == NULL ) {
  281. if( mysql_field_count(c->c) != 0 )
  282. error(c->c,rq);
  283. result *r = (result*)hl_gc_alloc_noptr(sizeof(result));
  284. memset(r,0,sizeof(result));
  285. r->nfields = (int)mysql_affected_rows(c->c);
  286. return r;
  287. }
  288. return alloc_result(c,res);
  289. }
  290. HL_PRIM vbyte *HL_NAME(escape)( connection *c, const char *str, int len ) {
  291. int wlen = len * 2;
  292. vbyte *sout = hl_gc_alloc_noptr(wlen+1);
  293. wlen = mysql_real_escape_string(c->c,(char*)sout,str,len);
  294. if( wlen < 0 ) {
  295. hl_buffer *b = hl_alloc_buffer();
  296. hl_buffer_cstr(b,"Unsupported charset : ");
  297. hl_buffer_cstr(b,mysql_character_set_name(c->c));
  298. hl_throw_buffer(b);
  299. }
  300. sout[wlen] = 0;
  301. return sout;
  302. }
  303. typedef struct {
  304. hl_type *t;
  305. const char *host;
  306. const char *user;
  307. const char *pass;
  308. const char *socket;
  309. int port;
  310. } cnx_params;
  311. HL_PRIM connection *HL_NAME(connect_wrap)( cnx_params *p ) {
  312. connection *c = (connection*)hl_gc_alloc_finalizer(sizeof(connection));
  313. memset(c,0,sizeof(connection));
  314. c->free = HL_NAME(close_wrap);
  315. c->c = mysql_init(NULL);
  316. if( mysql_real_connect(c->c,p->host,p->user,p->pass,NULL,p->port,p->socket,0) == NULL ) {
  317. hl_buffer *b = hl_alloc_buffer();
  318. hl_buffer_cstr(b, "Failed to connect to mysql server : ");
  319. hl_buffer_cstr(b,mysql_error(c->c));
  320. mysql_close(c->c);
  321. hl_throw_buffer(b);
  322. }
  323. return c;
  324. }
  325. HL_PRIM void HL_NAME(set_conv_funs)( vclosure *fstring, vclosure *fbytes, vclosure *fdate, vclosure *fjson ) {
  326. conv_string = fstring;
  327. conv_bytes = fbytes;
  328. conv_date = fdate;
  329. conv_json = fjson;
  330. }
  331. // ---------------------------------------------------------------
  332. // Registers
  333. #define _CNX _ABSTRACT(mysql_cnx)
  334. #define _RESULT _ABSTRACT(mysql_result)
  335. DEFINE_PRIM(_CNX, connect_wrap, _OBJ(_BYTES _BYTES _BYTES _BYTES _I32) );
  336. DEFINE_PRIM(_VOID, close_wrap, _CNX);
  337. DEFINE_PRIM(_RESULT, request, _CNX _BYTES _I32);
  338. DEFINE_PRIM(_BOOL, select_db_wrap, _CNX _BYTES);
  339. DEFINE_PRIM(_BYTES, escape, _CNX _BYTES _I32);
  340. DEFINE_PRIM(_I32, result_get_length, _RESULT);
  341. DEFINE_PRIM(_I32, result_get_nfields, _RESULT);
  342. DEFINE_PRIM(_ARR, result_get_fields_names, _RESULT);
  343. DEFINE_PRIM(_DYN, result_next, _RESULT);
  344. DEFINE_PRIM(_BYTES, result_get, _RESULT _I32);
  345. DEFINE_PRIM(_I32, result_get_int, _RESULT _I32);
  346. DEFINE_PRIM(_F64, result_get_float, _RESULT _I32);
  347. DEFINE_PRIM(_VOID, set_conv_funs, _DYN _DYN _DYN _DYN);
  348. /* ************************************************************************ */