mysql.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  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. static 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_I64
  49. } CONV;
  50. typedef struct {
  51. void *free;
  52. MYSQL_RES *r;
  53. int nfields;
  54. CONV *fields_convs;
  55. int *fields_ids;
  56. MYSQL_ROW current;
  57. } result;
  58. typedef struct {
  59. void *free;
  60. MYSQL *c;
  61. } connection;
  62. static vclosure *conv_string = NULL;
  63. static vclosure *conv_json = NULL;
  64. static vclosure *conv_bytes = NULL;
  65. static vclosure *conv_date = NULL;
  66. static void free_result( result *r ) {
  67. mysql_free_result(r->r);
  68. free(r->fields_ids);
  69. free(r->fields_convs);
  70. }
  71. HL_PRIM int HL_NAME(result_get_length)( result *r ) {
  72. if( r->r == NULL )
  73. return r->nfields;
  74. return (int)mysql_num_rows(r->r);
  75. }
  76. HL_PRIM int HL_NAME(result_get_nfields)( result *r ) {
  77. return r->nfields;
  78. }
  79. HL_PRIM varray *HL_NAME(result_get_fields_names)( result *r ) {
  80. int k;
  81. MYSQL_FIELD *fields = mysql_fetch_fields(r->r);
  82. varray *a = hl_alloc_array(&hlt_bytes,r->nfields);
  83. for(k=0;k<r->nfields;k++)
  84. hl_aptr(a,vbyte*)[k] = (vbyte*)fields[k].name;
  85. return a;
  86. }
  87. HL_PRIM vdynamic *HL_NAME(result_next)( result *r ) {
  88. unsigned long *lengths = NULL;
  89. MYSQL_ROW row = mysql_fetch_row(r->r);
  90. if( row == NULL )
  91. return NULL;
  92. int i;
  93. struct tm t;
  94. vdynamic *obj = (vdynamic*)hl_alloc_dynobj();
  95. vdynamic arg;
  96. vdynamic length;
  97. vdynamic *pargs[2];
  98. pargs[0] = &arg;
  99. pargs[1] = &length;
  100. length.t = &hlt_i32;
  101. r->current = row;
  102. for(i=0;i<r->nfields;i++) {
  103. if( row[i] == NULL ) continue;
  104. vdynamic *value = NULL;
  105. switch( r->fields_convs[i] ) {
  106. case CONV_INT:
  107. hl_dyn_seti(obj, r->fields_ids[i], &hlt_i32, atoi(row[i]));
  108. break;
  109. case CONV_I64:
  110. {
  111. char *endptr;
  112. hl_dyn_seti64(obj, r->fields_ids[i], strtoll(row[i],&endptr,10));
  113. }
  114. break;
  115. case CONV_STRING:
  116. arg.t = &hlt_bytes;
  117. arg.v.ptr = row[i];
  118. value = hl_dyn_call(conv_string, pargs, 1);
  119. break;
  120. case CONV_JSON:
  121. arg.t = &hlt_bytes;
  122. arg.v.ptr = row[i];
  123. value = hl_dyn_call(conv_json, pargs, 1);
  124. break;
  125. case CONV_BOOL:
  126. hl_dyn_seti(obj, r->fields_ids[i], &hlt_bool, (int)(*row[i] != '0'));
  127. break;
  128. case CONV_FLOAT:
  129. hl_dyn_setd(obj, r->fields_ids[i], atof(row[i]));
  130. break;
  131. case CONV_BINARY:
  132. if( lengths == NULL ) {
  133. lengths = mysql_fetch_lengths(r->r);
  134. if( lengths == NULL ) hl_error("mysql_fetch_lengths");
  135. }
  136. arg.t = &hlt_bytes;
  137. arg.v.ptr = row[i];
  138. length.v.i = lengths[i];
  139. value = hl_dyn_call(conv_bytes, pargs, 2);
  140. break;
  141. case CONV_DATE:
  142. sscanf(row[i],"%4d-%2d-%2d",&t.tm_year,&t.tm_mon,&t.tm_mday);
  143. t.tm_hour = 0;
  144. t.tm_min = 0;
  145. t.tm_sec = 0;
  146. t.tm_isdst = -1;
  147. t.tm_year -= 1900;
  148. t.tm_mon--;
  149. arg.t = &hlt_i32;
  150. arg.v.i = (int)mktime(&t);
  151. value = hl_dyn_call(conv_date,pargs, 1);
  152. break;
  153. case CONV_DATETIME:
  154. 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);
  155. t.tm_isdst = -1;
  156. t.tm_year -= 1900;
  157. t.tm_mon--;
  158. arg.t = &hlt_i32;
  159. arg.v.i = (int)mktime(&t);
  160. value = hl_dyn_call(conv_date,pargs, 1);
  161. break;
  162. default:
  163. break;
  164. }
  165. if( value ) hl_dyn_setp(obj, r->fields_ids[i], &hlt_dyn, value);
  166. }
  167. return obj;
  168. }
  169. HL_PRIM vbyte *HL_NAME(result_get)( result *r, int n ) {
  170. const char *str;
  171. if( n < 0 || n >= r->nfields )
  172. return NULL;
  173. if( !r->current ) {
  174. HL_NAME(result_next)(r);
  175. if( !r->current )
  176. return NULL;
  177. }
  178. str = r->current[n];
  179. return (vbyte*)(str ? str : "");
  180. }
  181. HL_PRIM int HL_NAME(result_get_int)( result *r, int n ) {
  182. const char *str;
  183. if( n < 0 || n >= r->nfields )
  184. return 0;
  185. if( !r->current ) {
  186. HL_NAME(result_next)(r);
  187. if( !r->current )
  188. return 0;
  189. }
  190. str = r->current[n];
  191. return str ? atoi(str) : 0;
  192. }
  193. HL_PRIM double HL_NAME(result_get_float)( result *r, int n ) {
  194. const char *str;
  195. if( n < 0 || n >= r->nfields )
  196. return 0.;
  197. if( !r->current ) {
  198. HL_NAME(result_next)(r);
  199. if( !r->current )
  200. return 0.;
  201. }
  202. str = r->current[n];
  203. return str ? atof(str) : 0.;
  204. }
  205. static CONV convert_type( enum enum_field_types t, int flags, unsigned int length ) {
  206. // FIELD_TYPE_TIME
  207. // FIELD_TYPE_YEAR
  208. // FIELD_TYPE_NEWDATE
  209. // FIELD_TYPE_NEWDATE + 2: // 5.0 MYSQL_TYPE_BIT
  210. switch( t ) {
  211. case FIELD_TYPE_TINY:
  212. if( length == 1 )
  213. return CONV_BOOL;
  214. case FIELD_TYPE_SHORT:
  215. case FIELD_TYPE_LONG:
  216. case FIELD_TYPE_INT24:
  217. return CONV_INT;
  218. case FIELD_TYPE_LONGLONG:
  219. return CONV_I64;
  220. case FIELD_TYPE_DECIMAL:
  221. case FIELD_TYPE_FLOAT:
  222. case FIELD_TYPE_DOUBLE:
  223. case 246: // 5.0 MYSQL_NEW_DECIMAL
  224. return CONV_FLOAT;
  225. case 245: // JSON
  226. return CONV_JSON;
  227. case FIELD_TYPE_BLOB:
  228. case FIELD_TYPE_TINY_BLOB:
  229. case FIELD_TYPE_MEDIUM_BLOB:
  230. case FIELD_TYPE_LONG_BLOB:
  231. if( (flags & BINARY_FLAG) != 0 )
  232. return CONV_BINARY;
  233. return CONV_STRING;
  234. case FIELD_TYPE_DATETIME:
  235. case FIELD_TYPE_TIMESTAMP:
  236. return CONV_DATETIME;
  237. case FIELD_TYPE_DATE:
  238. return CONV_DATE;
  239. case FIELD_TYPE_NULL:
  240. case FIELD_TYPE_ENUM:
  241. case FIELD_TYPE_SET:
  242. //case FIELD_TYPE_VAR_STRING:
  243. //case FIELD_TYPE_GEOMETRY:
  244. // 5.0 MYSQL_TYPE_VARCHAR
  245. default:
  246. if( (flags & BINARY_FLAG) != 0 )
  247. return CONV_BINARY;
  248. return CONV_STRING;
  249. }
  250. }
  251. static result *alloc_result( connection *c, MYSQL_RES *r ) {
  252. result *res = (result*)hl_gc_alloc_finalizer(sizeof(result));
  253. int num_fields = mysql_num_fields(r);
  254. int i;
  255. MYSQL_FIELD *fields = mysql_fetch_fields(r);
  256. res->free = free_result;
  257. res->r = r;
  258. res->current = NULL;
  259. res->nfields = num_fields;
  260. res->fields_ids = (int*)malloc(sizeof(int)*num_fields);
  261. res->fields_convs = (CONV*)malloc(sizeof(CONV)*num_fields);
  262. for(i=0;i<num_fields;i++) {
  263. int id;
  264. if( strchr(fields[i].name,'(') )
  265. id = hl_hash_gen(USTR("???"),true); // looks like an inner request : prevent hashing + cashing it
  266. else
  267. id = hl_hash_gen(hl_to_utf16(fields[i].name),true);
  268. res->fields_ids[i] = id;
  269. res->fields_convs[i] = convert_type(fields[i].type,fields[i].flags,fields[i].length);
  270. }
  271. return res;
  272. }
  273. // ---------------------------------------------------------------
  274. // Connection
  275. HL_PRIM void HL_NAME(close_wrap)( connection *c ) {
  276. if( c->c ) {
  277. mp_close(c->c);
  278. c->c = NULL;
  279. }
  280. }
  281. HL_PRIM bool HL_NAME(select_db_wrap)( connection *c, const char *db ) {
  282. return mysql_select_db(c->c,db) == 0;
  283. }
  284. HL_PRIM result *HL_NAME(request)( connection *c, const char *rq, int rqLen ) {
  285. if( mysql_real_query(c->c,rq,rqLen) != 0 )
  286. error(c->c,rq);
  287. MYSQL_RES *res = mysql_store_result(c->c);
  288. if( res == NULL ) {
  289. if( mysql_field_count(c->c) != 0 )
  290. error(c->c,rq);
  291. result *r = (result*)hl_gc_alloc_noptr(sizeof(result));
  292. memset(r,0,sizeof(result));
  293. r->nfields = (int)mysql_affected_rows(c->c);
  294. return r;
  295. }
  296. return alloc_result(c,res);
  297. }
  298. HL_PRIM vbyte *HL_NAME(escape)( connection *c, const char *str, int len ) {
  299. int wlen = len * 2;
  300. vbyte *sout = hl_gc_alloc_noptr(wlen+1);
  301. wlen = mysql_real_escape_string(c->c,(char*)sout,str,len);
  302. if( wlen < 0 ) {
  303. hl_buffer *b = hl_alloc_buffer();
  304. hl_buffer_cstr(b,"Unsupported charset : ");
  305. hl_buffer_cstr(b,mysql_character_set_name(c->c));
  306. hl_throw_buffer(b);
  307. }
  308. sout[wlen] = 0;
  309. return sout;
  310. }
  311. typedef struct {
  312. hl_type *t;
  313. const char *host;
  314. const char *user;
  315. const char *pass;
  316. const char *socket;
  317. int port;
  318. } cnx_params;
  319. HL_PRIM connection *HL_NAME(connect_wrap)( cnx_params *p ) {
  320. connection *c = (connection*)hl_gc_alloc_finalizer(sizeof(connection));
  321. memset(c,0,sizeof(connection));
  322. c->free = HL_NAME(close_wrap);
  323. c->c = mysql_init(NULL);
  324. if( mysql_real_connect(c->c,p->host,p->user,p->pass,NULL,p->port,p->socket,0) == NULL ) {
  325. hl_buffer *b = hl_alloc_buffer();
  326. hl_buffer_cstr(b, "Failed to connect to mysql server : ");
  327. hl_buffer_cstr(b,mysql_error(c->c));
  328. mysql_close(c->c);
  329. hl_throw_buffer(b);
  330. }
  331. return c;
  332. }
  333. HL_PRIM void HL_NAME(set_conv_funs)( vclosure *fstring, vclosure *fbytes, vclosure *fdate, vclosure *fjson ) {
  334. conv_string = fstring;
  335. conv_bytes = fbytes;
  336. conv_date = fdate;
  337. conv_json = fjson;
  338. }
  339. // ---------------------------------------------------------------
  340. // Registers
  341. #define _CNX _ABSTRACT(mysql_cnx)
  342. #define _RESULT _ABSTRACT(mysql_result)
  343. DEFINE_PRIM(_CNX, connect_wrap, _OBJ(_BYTES _BYTES _BYTES _BYTES _I32) );
  344. DEFINE_PRIM(_VOID, close_wrap, _CNX);
  345. DEFINE_PRIM(_RESULT, request, _CNX _BYTES _I32);
  346. DEFINE_PRIM(_BOOL, select_db_wrap, _CNX _BYTES);
  347. DEFINE_PRIM(_BYTES, escape, _CNX _BYTES _I32);
  348. DEFINE_PRIM(_I32, result_get_length, _RESULT);
  349. DEFINE_PRIM(_I32, result_get_nfields, _RESULT);
  350. DEFINE_PRIM(_ARR, result_get_fields_names, _RESULT);
  351. DEFINE_PRIM(_DYN, result_next, _RESULT);
  352. DEFINE_PRIM(_BYTES, result_get, _RESULT _I32);
  353. DEFINE_PRIM(_I32, result_get_int, _RESULT _I32);
  354. DEFINE_PRIM(_F64, result_get_float, _RESULT _I32);
  355. DEFINE_PRIM(_VOID, set_conv_funs, _DYN _DYN _DYN _DYN);
  356. /* ************************************************************************ */