mysql.c 9.8 KB

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