dclib-mysql.c 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716
  1. /***************************************************************************
  2. * *
  3. * _____ ____ *
  4. * | __ \ / __ \ _ _ _____ *
  5. * | | \ \ / / \_\ | | | | _ \ *
  6. * | | \ \| | | | | | |_| | *
  7. * | | | || | | | | | ___/ *
  8. * | | / /| | __ | | | | _ \ *
  9. * | |__/ / \ \__/ / | |___| | |_| | *
  10. * |_____/ \____/ |_____|_|_____/ *
  11. * *
  12. * Wiimms source code library *
  13. * *
  14. ***************************************************************************
  15. * *
  16. * Copyright (c) 2012-2022 by Dirk Clemens <wiimm@wiimm.de> *
  17. * *
  18. ***************************************************************************
  19. * *
  20. * This library is free software; you can redistribute it and/or modify *
  21. * it under the terms of the GNU General Public License as published by *
  22. * the Free Software Foundation; either version 2 of the License, or *
  23. * (at your option) any later version. *
  24. * *
  25. * This library is distributed in the hope that it will be useful, *
  26. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  27. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  28. * GNU General Public License for more details. *
  29. * *
  30. * See file gpl-2.0.txt or http://www.gnu.org/licenses/gpl-2.0.txt *
  31. * *
  32. ***************************************************************************/
  33. #define _GNU_SOURCE 1
  34. #include <string.h>
  35. #include <stddef.h>
  36. #include <mysql/mysql.h>
  37. #include <mysql/errmsg.h>
  38. #include "dclib-mysql.h"
  39. #include "dclib-file.h"
  40. #include "dclib-network.h"
  41. // http://dev.mysql.com/doc/refman/5.1/en/c-api-functions.html
  42. //
  43. ///////////////////////////////////////////////////////////////////////////////
  44. /////////////// global vars ///////////////
  45. ///////////////////////////////////////////////////////////////////////////////
  46. UsageDuration_t mysql_query_usage = { .par.used = 0, .par.enabled = true };
  47. const UsageCtrl_t mysql_query_usage_ctrl =
  48. {
  49. .par = &mysql_query_usage.par,
  50. .ud = &mysql_query_usage,
  51. .title = "Database queries",
  52. .key1 = "DB",
  53. .key2 = "MYSQL",
  54. .srt_prefix = "my-q-",
  55. };
  56. ///////////////////////////////////////////////////////////////////////////////
  57. const SaveRestoreTab_t SRT_Mysql[] =
  58. {
  59. #undef SRT_NAME
  60. #define SRT_NAME MySql_t
  61. DEF_SRT_COMMENT("mysql stats"),
  62. DEF_SRT_SEPARATOR(),
  63. DEF_SRT_MODE_ADD(),
  64. DEF_SRT_UINT( total_connect_count, "mystat-connect" ),
  65. DEF_SRT_UINT( total_query_count, "mystat-query-c" ),
  66. DEF_SRT_UINT( total_query_size, "mystat-query-s" ),
  67. DEF_SRT_UINT( total_result_count, "mystat-result" ),
  68. DEF_SRT_UINT( total_row_count, "mystat-row" ),
  69. DEF_SRT_UINT( total_field_count, "mystat-field-c" ),
  70. DEF_SRT_UINT( total_field_size, "mystat-field-s" ),
  71. DEF_SRT_SEPARATOR(),
  72. DEF_SRT_TERM()
  73. };
  74. //
  75. ///////////////////////////////////////////////////////////////////////////////
  76. /////////////// watch long queries ///////////////
  77. ///////////////////////////////////////////////////////////////////////////////
  78. static ccp wq_fname = 0; // NULL or opened file
  79. static LogFile_t wq_log = {0}; // log data
  80. static bool wq_failed = false; // true, if fopen() faild => don't try again
  81. static u_nsec_t wq_nsec = M1(wq_nsec); // >0: log queries that need ≥# nsec
  82. static uint wq_size = M1(wq_size); // >0: log queries with ≥# bytes
  83. ///////////////////////////////////////////////////////////////////////////////
  84. void SetupQueryLogMYSQL
  85. (
  86. ccp fname, // filename of log file, openend with mode "a"
  87. ccp tag, // identification of the tool for shared log files
  88. u_nsec_t nsec, // >0: log queries that need e# nsec
  89. uint size // >0: log queries that are longer e# bytes
  90. )
  91. {
  92. CloseQueryLogMYSQL();
  93. wq_fname = fname;
  94. wq_failed = false;
  95. wq_nsec = nsec ? nsec : M1(wq_nsec);
  96. wq_size = size ? size : M1(wq_size);
  97. wq_log.tag = MemByString0(tag);
  98. wq_log.ts_mode = TSM_MSEC;
  99. wq_log.flush = true;
  100. }
  101. ///////////////////////////////////////////////////////////////////////////////
  102. void CloseQueryLogMYSQL()
  103. {
  104. if (wq_log.log)
  105. {
  106. fclose(wq_log.log);
  107. wq_log.log = 0;
  108. }
  109. }
  110. ///////////////////////////////////////////////////////////////////////////////
  111. LogFile_t * OpenQueryLogMYSQL()
  112. {
  113. if (!wq_log.log)
  114. {
  115. if ( wq_failed || !wq_fname || !*wq_fname )
  116. {
  117. wq_failed = true;
  118. return 0;
  119. }
  120. wq_log.log = fopen(wq_fname,"ab");
  121. if (!wq_log.log)
  122. {
  123. wq_failed = true;
  124. return 0;
  125. }
  126. }
  127. return &wq_log;
  128. }
  129. //
  130. ///////////////////////////////////////////////////////////////////////////////
  131. /////////////// struct MySql_t ///////////////
  132. ///////////////////////////////////////////////////////////////////////////////
  133. // management
  134. void InitializeMYSQL ( MySql_t *my )
  135. {
  136. #if DEBUG
  137. static uint done = 0;
  138. if (!done)
  139. {
  140. done++;
  141. TRACE("- MYSQL\n");
  142. TRACE_SIZEOF(MySql_t);
  143. TRACE_SIZEOF(MySqlResult_t);
  144. TRACE_SIZEOF(MySqlStatus_t);
  145. TRACE_SIZEOF(st_mysql);
  146. TRACE_SIZEOF(st_mysql_res);
  147. TRACE_SIZEOF(st_mysql_field);
  148. }
  149. #endif
  150. DASSERT(my);
  151. memset(my,0,sizeof(*my));
  152. my->auto_reconnect = true;
  153. my->prefix = EmptyString;
  154. InitializeStatusMYSQL(&my->status);
  155. AddToUsageMgr(&mysql_query_usage_ctrl);
  156. }
  157. ///////////////////////////////////////////////////////////////////////////////
  158. void ResetMYSQL ( MySql_t *my )
  159. {
  160. DASSERT(my);
  161. CloseMYSQL(my);
  162. FREE((char*)my->server);
  163. FREE((char*)my->user);
  164. FREE((char*)my->password);
  165. FREE((char*)my->database);
  166. FreeString(my->prefix);
  167. InitializeMYSQL(my);
  168. }
  169. ///////////////////////////////////////////////////////////////////////////////
  170. enumError OpenMYSQL ( MySql_t *my, uint loglevel )
  171. {
  172. DASSERT(my);
  173. ClearStatusMYSQL(&my->status);
  174. if (my->mysql)
  175. return ERR_OK; // already connected
  176. if ( !my || !my->server )
  177. {
  178. if ( loglevel >= MYLL_ERROR )
  179. ERROR0(ERR_MISSING_PARAM,"No MySql server defined.\n");
  180. return ERR_MISSING_PARAM;
  181. }
  182. NetworkHost_t host;
  183. ResolveHost(&host,true,my->server,MYSQL_DEFAULT_PORT,false,true);
  184. PRINT("MYSQL CONNECT: %s:%u -> %s\n",
  185. host.name, host.port, PrintIP4(0,0,host.ip4,host.port) );
  186. static bool lib_init_done = false;
  187. if (!lib_init_done)
  188. {
  189. noPRINT("mysql_library_init()\n");
  190. if (mysql_library_init(0,NULL,NULL))
  191. {
  192. if ( loglevel >= MYLL_ERROR )
  193. ERROR0(ERR_DATABASE,"Can't initialize MySql library.\n");
  194. return ERR_DATABASE;
  195. }
  196. lib_init_done = true;
  197. }
  198. my->mysql = mysql_init(NULL);
  199. //HEXDUMP16(0,0,my->mysql,sizeof(*my->mysql));
  200. if (!my->mysql)
  201. {
  202. if ( loglevel >= MYLL_ERROR )
  203. ERROR0(ERR_DATABASE,"Can't initialize MySql data.\n");
  204. ResetHost(&host);
  205. return ERR_DATABASE;
  206. }
  207. if (my->auto_reconnect)
  208. {
  209. my_bool reconnect = 1;
  210. mysql_options(my->mysql,MYSQL_OPT_RECONNECT,&reconnect);
  211. }
  212. noPRINT("connect(%p,%s,%s,%s,%s,%u,,)\n",
  213. my->mysql, host.name, my->user, my->password, my->database, host.port );
  214. MYSQL *stat = mysql_real_connect ( my->mysql, host.name,
  215. my->user, my->password, my->database,
  216. host.port, NULL, 0 );
  217. if (!stat)
  218. {
  219. GetStatusMYSQL(&my->status,my->mysql);
  220. if ( loglevel >= MYLL_ERROR )
  221. ERROR0(ERR_CANT_CONNECT,"Can't connect to %s:\n-> %s\n",
  222. PrintIP4(0,0,host.ip4,host.port),my->status.message);
  223. ResetHost(&host);
  224. mysql_close(my->mysql);
  225. my->mysql = 0;
  226. return ERR_CANT_CONNECT;
  227. }
  228. mysql_set_character_set(my->mysql,"utf8mb4");
  229. my->total_connect_count++;
  230. ResetHost(&host);
  231. return ERR_OK;
  232. }
  233. ///////////////////////////////////////////////////////////////////////////////
  234. void CloseMYSQL ( MySql_t *my )
  235. {
  236. DASSERT(my);
  237. //--- close results
  238. FreeResultListMYSQL(my->first_result);
  239. my->first_result = 0;
  240. FreeResultListMYSQL(my->pool_result);
  241. my->pool_result = 0;
  242. //--- close database
  243. if (my->mysql)
  244. {
  245. mysql_close(my->mysql);
  246. my->mysql = 0;
  247. }
  248. //--- reset status
  249. ClearStatusMYSQL(&my->status);
  250. }
  251. ///////////////////////////////////////////////////////////////////////////////
  252. void DefineDatabase
  253. (
  254. MySql_t *my, // valid struct
  255. ccp server, // NULL or server name
  256. ccp user, // NULL or user name
  257. ccp password, // NULL or user password
  258. ccp database // NULL or name of database
  259. )
  260. {
  261. DASSERT(my);
  262. CloseMYSQL(my);
  263. if (server)
  264. {
  265. FREE((char*)my->server);
  266. my->server = STRDUP(server);
  267. }
  268. if (user)
  269. {
  270. FREE((char*)my->user);
  271. my->user = STRDUP(user);
  272. }
  273. if (password)
  274. {
  275. FREE((char*)my->password);
  276. my->password = STRDUP(password);
  277. }
  278. if (database)
  279. {
  280. FREE((char*)my->database);
  281. my->database = STRDUP(database);
  282. }
  283. FreeString(my->prefix);
  284. my->prefix = EmptyString;
  285. }
  286. ///////////////////////////////////////////////////////////////////////////////
  287. void DefineDatabasePrefix
  288. (
  289. MySql_t *my, // valid struct
  290. ccp prefix // NULL or default prefix, only for external usage
  291. )
  292. {
  293. DASSERT(my);
  294. FreeString(my->prefix);
  295. my->prefix = prefix && *prefix ? STRDUP(prefix) : EmptyString;
  296. }
  297. ///////////////////////////////////////////////////////////////////////////////
  298. static enumError CheckOpenMYSQL ( MySql_t *my, uint loglevel )
  299. {
  300. if (AutoOpenMYSQL(my,loglevel))
  301. return ERR_OK;
  302. if ( loglevel >= MYLL_ERROR )
  303. ERROR0(ERR_SEMANTIC,"No database connected.\n");
  304. return ERR_SEMANTIC;
  305. }
  306. //
  307. ///////////////////////////////////////////////////////////////////////////////
  308. ///////////////////////////////////////////////////////////////////////////////
  309. // queries
  310. static void update_query_duration
  311. ( MySql_t *my, u_nsec_t start_time, ccp query, uint qlen )
  312. {
  313. DASSERT(my);
  314. const u_usec_t dur_nsec = GetTimerNSec() - start_time;
  315. my->last_duration_usec = dur_nsec / NSEC_PER_USEC;
  316. if ( my->max_duration_usec < my->last_duration_usec )
  317. my->max_duration_usec = my->last_duration_usec;
  318. my->total_duration_usec += my->last_duration_usec;
  319. UpdateUsageDurationIncrement(&mysql_query_usage,dur_nsec);
  320. if ( dur_nsec >= wq_nsec || qlen >= wq_size )
  321. {
  322. LogFile_t *lf = OpenQueryLogMYSQL();
  323. if (lf)
  324. {
  325. char buf[2000], *dest = buf;
  326. bool have_space = false;
  327. while ( *query && dest < buf+sizeof(buf)-2 )
  328. {
  329. const uchar ch = *query++;
  330. if ( ch > ' ' )
  331. {
  332. if (have_space)
  333. {
  334. have_space = false;
  335. *dest++ = ' ';
  336. }
  337. *dest++ = ch;
  338. }
  339. else if ( dest > buf )
  340. have_space = true;
  341. }
  342. *dest = 0;
  343. PrintLogFile(lf,"%5u %s : %s\n",
  344. qlen,
  345. PrintTimerNSec6(0,0,dur_nsec,DC_SFORM_ALIGN|DC_SFORM_DASH),
  346. buf );
  347. }
  348. }
  349. }
  350. //-----------------------------------------------------------------------------
  351. enumError DoQueryMYSQL
  352. (
  353. MySql_t *my, // valid struct
  354. LogLevelMYSQL loglevel, // log level for mysql errors and queries
  355. ccp query, // query string
  356. int query_length // length of 'query', -1 if unknown
  357. )
  358. {
  359. DASSERT(my);
  360. DASSERT(query);
  361. const u_nsec_t start_time = GetTimerNSec();
  362. enumError err = CheckOpenMYSQL(my,loglevel);
  363. if (err)
  364. return err;
  365. if ( query_length < 0 )
  366. query_length = strlen(query);
  367. my->total_query_count++;
  368. my->total_query_size += query_length;
  369. if (mysql_real_query(my->mysql,query,query_length))
  370. {
  371. TRACE("QUERY: %.*s\n",query_length,query);
  372. my->field_count = 0;
  373. GetStatusMYSQL(&my->status,my->mysql);
  374. bool fail = true;
  375. if ( my->status.status == CR_SERVER_GONE_ERROR && my->auto_reconnect )
  376. {
  377. MySqlStatus_t save;
  378. MoveStatusMYSQL(&save,true,&my->status);
  379. CloseMYSQL(my);
  380. if ( OpenMYSQL(my,loglevel) || mysql_real_query(my->mysql,query,query_length) )
  381. MoveStatusMYSQL(&my->status,false,&save);
  382. else
  383. {
  384. ClearStatusMYSQL(&save);
  385. fail = false;
  386. }
  387. }
  388. if (fail)
  389. {
  390. if ( loglevel >= MYLL_QUERY_ON_ERROR )
  391. ERROR0(ERR_DATABASE,"%s (#%d)\n--QUERY--\n%.*s\n",
  392. my->status.message, my->status.status,
  393. query_length, query );
  394. else if ( loglevel >= MYLL_ERROR )
  395. ERROR0(ERR_DATABASE,"%s (#%d)\n",
  396. my->status.message, my->status.status );
  397. update_query_duration(my,start_time,query,query_length);
  398. return ERR_DATABASE;
  399. }
  400. }
  401. if ( loglevel >= MYLL_QUERY_ALWAYS )
  402. ERROR0(ERR_OK,"%.*s\n", query_length, query );
  403. my->field_count = mysql_field_count(my->mysql);
  404. ClearStatusMYSQL(&my->status);
  405. update_query_duration(my,start_time,query,query_length);
  406. return ERR_OK;
  407. }
  408. ///////////////////////////////////////////////////////////////////////////////
  409. enumError PrintArgQueryMYSQL
  410. (
  411. MySql_t *my, // valid struct
  412. LogLevelMYSQL loglevel, // log level for mysql errors and queries
  413. ccp format, // format string for vsnprintf()
  414. va_list arg // parameters for 'format'
  415. )
  416. {
  417. DASSERT(my);
  418. DASSERT(format);
  419. char buf[10000];
  420. va_list arg2;
  421. va_copy(arg2,arg);
  422. int stat = vsnprintf(buf,sizeof(buf),format,arg2);
  423. va_end(arg2);
  424. if ( stat < sizeof(buf) )
  425. return DoQueryMYSQL(my,loglevel,buf,stat);
  426. //--- buffer too small, use dynamic memory
  427. noPRINT("PrintQueryMYSQL() -> MALLOC(%u)\n",stat+1);
  428. char *dest = MALLOC(stat+1);
  429. stat = vsnprintf(dest,stat+1,format,arg);
  430. const enumError err = DoQueryMYSQL(my,loglevel,dest,stat);
  431. FREE(dest);
  432. return err;
  433. }
  434. ///////////////////////////////////////////////////////////////////////////////
  435. enumError PrintQueryMYSQL
  436. (
  437. MySql_t *my, // valid struct
  438. LogLevelMYSQL loglevel, // log level for mysql errors and queries
  439. ccp format, // format string for vsnprintf()
  440. ... // parameters for 'format'
  441. )
  442. {
  443. DASSERT(my);
  444. DASSERT(format);
  445. va_list arg;
  446. va_start(arg,format);
  447. enumError err = PrintArgQueryMYSQL(my,loglevel,format,arg);
  448. va_end(arg);
  449. return err;
  450. }
  451. //
  452. ///////////////////////////////////////////////////////////////////////////////
  453. ///////////////////////////////////////////////////////////////////////////////
  454. // support of multi queries
  455. mem_t GetFirstQuery ( ccp src, int src_len )
  456. {
  457. if (!src)
  458. {
  459. mem_t res = {0,0};
  460. return res;
  461. }
  462. ccp ptr = src;
  463. ccp end = ptr + ( src_len < 0 ? strlen(src) : src_len );
  464. //--- skip all leading blanks, controls and semicolons
  465. while ( ptr < end && ( *ptr >= 0 && *ptr <= ' ' || *ptr == ';' ) )
  466. ptr++;
  467. if ( ptr == end )
  468. {
  469. mem_t res = {ptr,0};
  470. return res;
  471. }
  472. ccp start = ptr;
  473. while ( ptr < end )
  474. {
  475. const char ch = *ptr++;
  476. if ( ch == ';' )
  477. {
  478. mem_t res = {start,ptr-start-1};
  479. return res;
  480. }
  481. if ( ch == '\\' && ptr < end )
  482. ptr++;
  483. else if ( ch == '\'' || ch == '\"' )
  484. {
  485. while ( ptr < end )
  486. {
  487. const char ch2 = *ptr++;
  488. if ( ch2 == '\\' && ptr < end )
  489. ptr++;
  490. else if ( ch2 == ch )
  491. break;
  492. }
  493. }
  494. }
  495. mem_t res = {start,ptr-start};
  496. return res;
  497. }
  498. ///////////////////////////////////////////////////////////////////////////////
  499. enumError DoMultiQueryMYSQL
  500. (
  501. MySql_t *my, // valid struct
  502. LogLevelMYSQL loglevel, // log level for mysql errors and queries
  503. ccp query, // query string
  504. int query_length // length of 'query', -1 if unknown
  505. )
  506. {
  507. DASSERT(my);
  508. DASSERT(query);
  509. mem_t q;
  510. q.ptr = query;
  511. q.len = query_length < 0 ? strlen(query) : query_length;
  512. for(;;)
  513. {
  514. mem_t q1 = GetFirstQuery(q.ptr,q.len);
  515. if (!q1.len)
  516. break;
  517. const enumError err = DoQueryMYSQL(my,loglevel,q1.ptr,q1.len);
  518. if (err)
  519. return err;
  520. q = BehindMem(q,q1.ptr+q1.len);
  521. }
  522. return ERR_OK;
  523. }
  524. ///////////////////////////////////////////////////////////////////////////////
  525. enumError PrintMultiQueryMYSQL
  526. (
  527. MySql_t *my, // valid struct
  528. LogLevelMYSQL loglevel, // log level for mysql errors and queries
  529. ccp format, // format string for vsnprintf()
  530. ... // parameters for 'format'
  531. )
  532. {
  533. DASSERT(my);
  534. DASSERT(format);
  535. char buf[10000];
  536. va_list arg;
  537. va_start(arg,format);
  538. int stat = vsnprintf(buf,sizeof(buf),format,arg);
  539. va_end(arg);
  540. if ( stat < sizeof(buf) )
  541. return DoMultiQueryMYSQL(my,loglevel,buf,stat);
  542. //--- buffer too small, use dynamic memory
  543. noPRINT("PrintQueryMYSQL() -> MALLOC(%u)\n",stat+1);
  544. char *dest = MALLOC(stat+1);
  545. va_start(arg,format);
  546. stat = vsnprintf(dest,stat+1,format,arg);
  547. va_end(arg);
  548. const enumError err = DoMultiQueryMYSQL(my,loglevel,dest,stat);
  549. FREE(dest);
  550. return err;
  551. }
  552. //
  553. ///////////////////////////////////////////////////////////////////////////////
  554. ///////////////////////////////////////////////////////////////////////////////
  555. // temp buffer support
  556. mem_t CopyMemMYSQL ( MySql_t * my, mem_t * src ) // 'src' may be NULL
  557. {
  558. if ( src && src->len > 0 )
  559. {
  560. if ( src->len < sizeof(my->tempbuf) && !my->tempbuf_used )
  561. {
  562. noPRINT("MYSQL: use tempbuf(%u)\n",src->len);
  563. memcpy(my->tempbuf,src->ptr,src->len);
  564. my->tempbuf[src->len] = 0;
  565. my->tempbuf_used = true;
  566. mem_t res = { my->tempbuf, src->len };
  567. return res;
  568. }
  569. return DupMem(*src);
  570. }
  571. mem_t res = {NULL,0};
  572. return res;
  573. }
  574. ///////////////////////////////////////////////////////////////////////////////
  575. void FreeMemMYSQL ( MySql_t * my, mem_t mem )
  576. {
  577. DASSERT(my);
  578. if ( mem.ptr == my->tempbuf )
  579. {
  580. noPRINT("MYSQL: free tempbuf\n");
  581. my->tempbuf_used = false;
  582. }
  583. else
  584. FREE((char*)mem.ptr);
  585. }
  586. //
  587. ///////////////////////////////////////////////////////////////////////////////
  588. ///////////////////////////////////////////////////////////////////////////////
  589. // fetch single value as result of a query
  590. mem_t FetchScalarMYSQL // FREE the result!
  591. (
  592. MySql_t *my, // valid struct
  593. LogLevelMYSQL loglevel // log level for mysql errors and queries
  594. )
  595. {
  596. DASSERT(my);
  597. mem_t ret = {NULL,0};
  598. MySqlResult_t *res = UseResultMYSQL(my,loglevel);
  599. if (res)
  600. {
  601. ret = CopyMemMYSQL(my,GetNextRowMYSQL(res));
  602. while (GetNextRowMYSQL(res)) // get all rows
  603. ;
  604. FreeResultMYSQL(res);
  605. }
  606. return ret;
  607. }
  608. ///////////////////////////////////////////////////////////////////////////////
  609. s64 FetchIntMYSQL
  610. (
  611. MySql_t *my, // valid struct
  612. LogLevelMYSQL loglevel, // log level for mysql errors and queries
  613. bool allow_trail, // allow additional chars behind number
  614. s64 return_default // return this value on non existent result
  615. )
  616. {
  617. DASSERT(my);
  618. mem_t res = FetchScalarMYSQL(my,loglevel);
  619. if (!res.len)
  620. return return_default;
  621. char *end;
  622. const s64 val = strtoll(res.ptr,&end,10);
  623. FreeMemMYSQL(my,res);
  624. return allow_trail || end == res.ptr + res.len ? val : return_default;
  625. }
  626. ///////////////////////////////////////////////////////////////////////////////
  627. u64 FetchUIntMYSQL
  628. (
  629. MySql_t *my, // valid struct
  630. LogLevelMYSQL loglevel, // log level for mysql errors and queries
  631. bool allow_trail, // allow additional chars behind number
  632. u64 return_default // return this value on non existent result
  633. )
  634. {
  635. DASSERT(my);
  636. mem_t res = FetchScalarMYSQL(my,loglevel);
  637. if (!res.len)
  638. return return_default;
  639. char *end;
  640. const u64 val = strtoull(res.ptr,&end,10);
  641. FreeMemMYSQL(my,res);
  642. return allow_trail || end == res.ptr + res.len ? val : return_default;
  643. }
  644. //
  645. ///////////////////////////////////////////////////////////////////////////////
  646. ///////////////////////////////////////////////////////////////////////////////
  647. // print query & fetch single value as result
  648. mem_t PrintArgFetchScalarMYSQL
  649. (
  650. // if res.len>0: FREE the result using FreeMemMYSQL(my,mem)
  651. MySql_t *my, // valid struct
  652. LogLevelMYSQL loglevel, // log level for mysql errors and queries
  653. ccp format, // format string for vsnprintf()
  654. va_list arg // parameters for 'format'
  655. )
  656. {
  657. DASSERT(my);
  658. DASSERT(format);
  659. mem_t ret = {NULL,0};
  660. if (!PrintArgQueryMYSQL(my,loglevel,format,arg))
  661. {
  662. MySqlResult_t *res = UseResultMYSQL(my,loglevel);
  663. if (res)
  664. {
  665. ret = CopyMemMYSQL(my,GetNextRowMYSQL(res));
  666. while (GetNextRowMYSQL(res)) // get all rows
  667. ;
  668. FreeResultMYSQL(res);
  669. }
  670. }
  671. return ret;
  672. }
  673. ///////////////////////////////////////////////////////////////////////////////
  674. mem_t PrintFetchScalarMYSQL
  675. (
  676. // if res.len>0: FREE the result using FreeMemMYSQL(my,mem)
  677. MySql_t *my, // valid struct
  678. LogLevelMYSQL loglevel, // log level for mysql errors and queries
  679. ccp format, // format string for vsnprintf()
  680. ... // parameters for 'format'
  681. )
  682. {
  683. DASSERT(my);
  684. DASSERT(format);
  685. va_list arg;
  686. va_start(arg,format);
  687. mem_t res = PrintArgFetchScalarMYSQL(my,loglevel,format,arg);
  688. va_end(arg);
  689. return res;
  690. }
  691. ///////////////////////////////////////////////////////////////////////////////
  692. s64 PrintFetchIntMYSQL
  693. (
  694. MySql_t *my, // valid struct
  695. LogLevelMYSQL loglevel, // log level for mysql errors and queries
  696. bool allow_trail, // allow additional chars behind number
  697. s64 return_default, // return this value on non existent result
  698. ccp format, // format string for vsnprintf()
  699. ... // parameters for 'format'
  700. )
  701. {
  702. DASSERT(my);
  703. DASSERT(format);
  704. va_list arg;
  705. va_start(arg,format);
  706. mem_t res = PrintArgFetchScalarMYSQL(my,loglevel,format,arg);
  707. va_end(arg);
  708. if (!res.len)
  709. return return_default;
  710. char *end;
  711. const s64 val = strtoll(res.ptr,&end,10);
  712. FreeMemMYSQL(my,res);
  713. return allow_trail || end == res.ptr + res.len ? val : return_default;
  714. }
  715. ///////////////////////////////////////////////////////////////////////////////
  716. u64 PrintFetchUIntMYSQL
  717. (
  718. MySql_t *my, // valid struct
  719. LogLevelMYSQL loglevel, // log level for mysql errors and queries
  720. bool allow_trail, // allow additional chars behind number
  721. u64 return_default, // return this value on non existent result
  722. ccp format, // format string for vsnprintf()
  723. ... // parameters for 'format'
  724. )
  725. {
  726. DASSERT(my);
  727. DASSERT(format);
  728. va_list arg;
  729. va_start(arg,format);
  730. mem_t res = PrintArgFetchScalarMYSQL(my,loglevel,format,arg);
  731. va_end(arg);
  732. if (!res.len)
  733. return return_default;
  734. char *end;
  735. const u64 val = strtoull(res.ptr,&end,10);
  736. FreeMemMYSQL(my,res);
  737. return allow_trail || end == res.ptr + res.len ? val : return_default;
  738. }
  739. //
  740. ///////////////////////////////////////////////////////////////////////////////
  741. ///////////////////////////////////////////////////////////////////////////////
  742. // fetch single row
  743. void * FetchSingleRowN
  744. (
  745. // returns NULL on error or emtpy result,
  746. // or a temporary buffer => call FREE(result)
  747. // following rows will be skipped
  748. MySql_t *my, // valid struct
  749. LogLevelMYSQL loglevel, // log level for mysql errors and queries
  750. mem_t *dest, // dest buffer, unused elements are set to {0,0}
  751. uint n_dest // number of elements in 'dest'
  752. )
  753. {
  754. DASSERT(my);
  755. DASSERT( dest || !n_dest );
  756. memset(dest,0,sizeof(*dest)*n_dest);
  757. char *buf = 0;
  758. MySqlResult_t *res = UseResultMYSQL(my,loglevel);
  759. if (res)
  760. {
  761. mem_t *row = GetNextRowMYSQL(res);
  762. if (row)
  763. {
  764. if ( n_dest > res->field_count )
  765. n_dest = res->field_count;
  766. //--- count memory usage and alloc buffer
  767. uint i, need = 0;
  768. for ( i = 0; i < n_dest; i++ )
  769. if ( row[i].len )
  770. need += row[i].len + 1;
  771. //--- get row data
  772. buf = MALLOC(need);
  773. char *ptr = buf;
  774. for ( i = 0; i < n_dest; i++, row++, dest++ )
  775. {
  776. if ( row->len )
  777. {
  778. dest->ptr = ptr;
  779. memcpy(ptr,row->ptr,row->len);
  780. dest->len = row->len;
  781. ptr += row->len;
  782. *ptr++ = 0;
  783. DASSERT( ptr <= buf+need );
  784. }
  785. }
  786. DASSERT( ptr == buf+need );
  787. //--- get and ignore all remaining rows
  788. while (GetNextRowMYSQL(res))
  789. ;
  790. }
  791. FreeResultMYSQL(res);
  792. }
  793. return buf;
  794. }
  795. ///////////////////////////////////////////////////////////////////////////////
  796. ///////////////////////////////////////////////////////////////////////////////
  797. int FetchSingleRowList
  798. (
  799. // returns -1 on error, 0 on empty result or the number of retrieved field
  800. // following rows will be skipped
  801. MySql_t *my, // valid struct
  802. LogLevelMYSQL loglevel, // log level for mysql errors and queries
  803. mem_list_t *dest, // destination list
  804. bool init_dest, // true: initialize 'dest'
  805. bool replace_null // true: replace NULL by EmptyString
  806. )
  807. {
  808. DASSERT(my);
  809. DASSERT(dest);
  810. if (init_dest)
  811. InitializeMemList(dest);
  812. dest->used = 0;
  813. int stat = -1;
  814. MySqlResult_t *res = UseResultMYSQL(my,loglevel);
  815. if (res)
  816. {
  817. stat = 0;
  818. mem_t *row = GetNextRowMYSQL(res);
  819. if (row)
  820. {
  821. stat = res->field_count;
  822. AssignMemListN(dest,row,stat,replace_null?3:0);
  823. //--- get and ignore all remaining rows
  824. while (GetNextRowMYSQL(res))
  825. ;
  826. }
  827. FreeResultMYSQL(res);
  828. }
  829. return stat;
  830. }
  831. //
  832. ///////////////////////////////////////////////////////////////////////////////
  833. ///////////////////////////////////////////////////////////////////////////////
  834. // count tables and columns
  835. int CountTablesMYSQL
  836. (
  837. MySql_t *my, // valid DB connection
  838. ccp table, // like "table"; if NULL|EMPTY: count tables
  839. ccp database // database name; if NULL|EMPTY: use default DB
  840. )
  841. {
  842. DASSERT(my);
  843. int stat = -1;
  844. mem_t db = EscapeStringMYSQL(my, database && *database ? database : my->database );
  845. mem_t tab = EscapeStringMYSQL(my, table && *table ? table : "%" );
  846. stat = PrintFetchIntMYSQL(my,MYLL_QUERY_ON_ERROR,false,-1,
  847. "SELECT COUNT(DISTINCT TABLE_NAME) FROM information_schema.COLUMNS\n"
  848. "WHERE TABLE_SCHEMA = \"%s\" && TABLE_NAME like \"%s\"\n",
  849. db.ptr, tab.ptr );
  850. FreeString(tab.ptr);
  851. FreeString(db.ptr);
  852. return stat;
  853. }
  854. ///////////////////////////////////////////////////////////////////////////////
  855. int CountColumnsMYSQL
  856. (
  857. MySql_t *my, // valid DB connection
  858. ccp column, // column name; if NULL|EMPTY: count columns
  859. ccp table, // like "table"; if NULL|EMPTY: all tables
  860. ccp database // database name; if NULL|EMPTY: use default DB
  861. )
  862. {
  863. DASSERT(my);
  864. int stat = -1;
  865. mem_t db = EscapeStringMYSQL(my, database && *database ? database : my->database );
  866. mem_t tab = EscapeStringMYSQL(my, table && *table ? table : "%" );
  867. if ( column && *column )
  868. {
  869. mem_t col = EscapeStringMYSQL(my,column);
  870. stat = PrintFetchIntMYSQL(my,MYLL_QUERY_ON_ERROR,false,-1,
  871. "SELECT COUNT(*) FROM information_schema.COLUMNS\n"
  872. "WHERE TABLE_SCHEMA = \"%s\" && TABLE_NAME like \"%s\""
  873. " && COLUMN_NAME = \"%s\"\n",
  874. db.ptr, tab.ptr, col.ptr );
  875. FreeString(col.ptr);
  876. }
  877. else
  878. {
  879. stat = PrintFetchIntMYSQL(my,MYLL_QUERY_ON_ERROR,false,-1,
  880. "SELECT COUNT(*) FROM information_schema.COLUMNS\n"
  881. "WHERE TABLE_SCHEMA = \"%s\" && TABLE_NAME like \"%s\"\n",
  882. db.ptr, tab.ptr );
  883. }
  884. FreeString(tab.ptr);
  885. FreeString(db.ptr);
  886. return stat;
  887. }
  888. //
  889. ///////////////////////////////////////////////////////////////////////////////
  890. ///////////////////////////////////////////////////////////////////////////////
  891. // helpers
  892. mem_t EscapeMYSQL ( MySql_t *my, cvp ptr, int len )
  893. {
  894. DASSERT(my);
  895. if ( len < 0 )
  896. len = ptr ? strlen(ptr) : 0;
  897. mem_t res;
  898. if ( !ptr || !len )
  899. {
  900. res.ptr = EmptyString;
  901. res.len = 0;
  902. }
  903. else
  904. {
  905. char *buf = MALLOC(2*len+1);
  906. res.ptr = buf;
  907. res.len = mysql_real_escape_string(my->mysql,buf,ptr,len);
  908. }
  909. return res;
  910. }
  911. //-----------------------------------------------------------------------------
  912. mem_t EscapeMYSQLCirc ( MySql_t *my, cvp ptr, int len )
  913. {
  914. DASSERT(my);
  915. if ( len < 0 )
  916. len = ptr ? strlen(ptr) : 0;
  917. mem_t res;
  918. if ( !ptr || !len )
  919. {
  920. res.ptr = EmptyString;
  921. res.len = 0;
  922. }
  923. else if ( len >= CIRC_BUF_MAX_ALLOC )
  924. {
  925. // no chance
  926. res.ptr = 0;
  927. res.len = 0;
  928. }
  929. else
  930. {
  931. char buf[2*CIRC_BUF_MAX_ALLOC+10];
  932. res.len = mysql_real_escape_string(my->mysql,buf,ptr,len);
  933. if ( res.len < CIRC_BUF_MAX_ALLOC )
  934. res.ptr = CopyCircBuf(buf,res.len+1);
  935. else
  936. {
  937. res.ptr = 0;
  938. res.len = 0;
  939. }
  940. }
  941. return res;
  942. }
  943. ///////////////////////////////////////////////////////////////////////////////
  944. mem_t QuoteMYSQL ( MySql_t *my, cvp ptr, int len, bool null_if_empty )
  945. {
  946. if ( len < 0 )
  947. len = ptr ? strlen(ptr) : 0;
  948. mem_t res;
  949. if ( !ptr || !len && null_if_empty )
  950. {
  951. res.ptr = STRDUP("NULL");
  952. res.len = 4;
  953. }
  954. else if (!len)
  955. {
  956. res.ptr = EmptyQuote;
  957. res.len = 0;
  958. }
  959. else
  960. {
  961. char *buf = MALLOC(2*len+3);
  962. res.ptr = buf;
  963. res.len = mysql_real_escape_string(my->mysql,buf+1,ptr,len) + 2;
  964. buf[0] = buf[res.len-1] = '"';
  965. buf[res.len] = 0;
  966. }
  967. return res;
  968. }
  969. //-----------------------------------------------------------------------------
  970. mem_t QuoteMYSQLCirc ( MySql_t *my, cvp ptr, int len, bool null_if_empty )
  971. {
  972. if ( len < 0 )
  973. len = ptr ? strlen(ptr) : 0;
  974. mem_t res;
  975. if ( !ptr || !len && null_if_empty )
  976. {
  977. res.ptr = CopyCircBuf("NULL",5);
  978. res.len = 4;
  979. }
  980. else if (!len)
  981. {
  982. res.ptr = EmptyQuote;
  983. res.len = 2;
  984. }
  985. else if ( len >= CIRC_BUF_MAX_ALLOC-2 )
  986. {
  987. // no chance
  988. res.ptr = 0;
  989. res.len = 0;
  990. }
  991. else
  992. {
  993. char buf[2*CIRC_BUF_MAX_ALLOC+10];
  994. res.len = mysql_real_escape_string(my->mysql,buf+1,ptr,len) + 2;
  995. if ( res.len < CIRC_BUF_MAX_ALLOC )
  996. {
  997. buf[0] = buf[res.len-1] = '"';
  998. buf[res.len] = 0;
  999. res.ptr = CopyCircBuf(buf,res.len+1);
  1000. }
  1001. else
  1002. {
  1003. res.ptr = 0;
  1004. res.len = 0;
  1005. }
  1006. }
  1007. return res;
  1008. }
  1009. ///////////////////////////////////////////////////////////////////////////////
  1010. TransferStats_t GetStatsMYSQL ( MySql_t *my )
  1011. {
  1012. TransferStats_t tf;
  1013. memset(&tf,0,sizeof(tf));
  1014. if (my)
  1015. {
  1016. tf.conn_count = my->total_connect_count;
  1017. tf.recv_count = my->total_row_count;
  1018. tf.recv_size = my->total_field_size;
  1019. tf.send_count = my->total_query_count;
  1020. tf.send_size = my->total_query_size;
  1021. }
  1022. return tf;
  1023. }
  1024. //
  1025. ///////////////////////////////////////////////////////////////////////////////
  1026. /////////////// struct MySqlResult_t ///////////////
  1027. ///////////////////////////////////////////////////////////////////////////////
  1028. static void InsertResultMYSQL ( MySqlResult_t ** first, MySqlResult_t * res )
  1029. {
  1030. DASSERT(first);
  1031. DASSERT(res);
  1032. DASSERT( res != *first ); // already cleared!
  1033. //--- remove res from previous list
  1034. if (res->prev_result)
  1035. res->prev_result->next_result = res->next_result;
  1036. if (res->next_result)
  1037. res->next_result->prev_result = res->prev_result;
  1038. //--- insert at top of the new list
  1039. res->prev_result = 0;
  1040. res->next_result = *first;
  1041. if (*first)
  1042. (*first)->prev_result = res;
  1043. *first = res;
  1044. FREE(res->row);
  1045. res->row = 0;
  1046. }
  1047. ///////////////////////////////////////////////////////////////////////////////
  1048. MySqlResult_t * UseResultMYSQL ( MySql_t *my, uint loglevel )
  1049. {
  1050. DASSERT(my);
  1051. enumError err = CheckOpenMYSQL(my,loglevel);
  1052. if (err)
  1053. {
  1054. AssignStatusMYSQL(&my->status,1,"No connection to database!",1);
  1055. return NULL;
  1056. }
  1057. MYSQL_RES *myres = mysql_use_result(my->mysql);
  1058. if (!myres)
  1059. {
  1060. GetStatusMYSQL(&my->status,my->mysql);
  1061. if ( loglevel >= MYLL_ERROR )
  1062. ERROR0(ERR_DATABASE,"%s\n",my->status.message);
  1063. return NULL;
  1064. }
  1065. my->total_result_count++;
  1066. MySqlResult_t *res;
  1067. if (my->pool_result)
  1068. {
  1069. res = my->pool_result;
  1070. my->pool_result = res->next_result;
  1071. }
  1072. else
  1073. res = CALLOC(1,sizeof(*res));
  1074. InsertResultMYSQL(&my->first_result,res);
  1075. res->mysql = my;
  1076. res->myres = myres;
  1077. res->loglevel = loglevel;
  1078. res->row_count = 0;
  1079. res->field_count = mysql_num_fields(myres);
  1080. res->row = CALLOC(sizeof(*res->row),res->field_count);
  1081. GetStatusMYSQL(&res->status,my->mysql);
  1082. return res;
  1083. }
  1084. ///////////////////////////////////////////////////////////////////////////////
  1085. void FreeResultMYSQL ( MySqlResult_t * res )
  1086. {
  1087. if (res)
  1088. {
  1089. MySql_t *my = res->mysql;
  1090. DASSERT(my);
  1091. CloseResultMYSQL(res);
  1092. ClearStatusMYSQL(&res->status);
  1093. if ( my->first_result == res )
  1094. my->first_result = res->next_result;
  1095. InsertResultMYSQL(&my->pool_result,res);
  1096. }
  1097. }
  1098. ///////////////////////////////////////////////////////////////////////////////
  1099. void CloseResultMYSQL ( MySqlResult_t * res )
  1100. {
  1101. DASSERT(res);
  1102. if (res->myres)
  1103. {
  1104. mysql_free_result(res->myres);
  1105. res->myres = 0;
  1106. }
  1107. FREE(res->row);
  1108. res->row = 0;
  1109. res->field_count = 0;
  1110. }
  1111. ///////////////////////////////////////////////////////////////////////////////
  1112. void FreeResultListMYSQL ( MySqlResult_t * first )
  1113. {
  1114. while (first)
  1115. {
  1116. MySqlResult_t *res = first;
  1117. first = res->next_result;
  1118. CloseResultMYSQL(res);
  1119. ClearStatusMYSQL(&res->status);
  1120. FREE(res);
  1121. }
  1122. }
  1123. ///////////////////////////////////////////////////////////////////////////////
  1124. mem_t * GetNextRowMYSQL ( MySqlResult_t * res )
  1125. {
  1126. DASSERT(res);
  1127. if ( !res || !res->myres || !res->row )
  1128. return NULL;
  1129. MYSQL_ROW myrow = mysql_fetch_row(res->myres);
  1130. ulong *mylen = mysql_fetch_lengths(res->myres);
  1131. res->myrow = myrow;
  1132. if ( !myrow || !mylen )
  1133. {
  1134. FREE(res->row);
  1135. res->row = 0;
  1136. return NULL;
  1137. }
  1138. res->mysql->total_row_count++;
  1139. mem_t *dest = res->row;
  1140. uint n = res->field_count;
  1141. res->mysql->total_field_count += n;
  1142. while ( n-- > 0 )
  1143. {
  1144. dest->ptr = *myrow++;
  1145. dest->len = *mylen++;
  1146. res->mysql->total_field_size += dest->len;
  1147. noPRINT("%3u: |%.*s|\n",dest->len,dest->len<50?dest->len:50,dest->ptr);
  1148. dest++;
  1149. }
  1150. return res->row;
  1151. }
  1152. //
  1153. ///////////////////////////////////////////////////////////////////////////////
  1154. /////////////// struct MySqlStatus_t ///////////////
  1155. ///////////////////////////////////////////////////////////////////////////////
  1156. void ClearStatusMYSQL ( MySqlStatus_t *stat )
  1157. {
  1158. DASSERT(stat);
  1159. if (stat->alloced)
  1160. {
  1161. FREE((char*)stat->message);
  1162. stat->alloced = false;
  1163. }
  1164. stat->message = stat->msgbuf;
  1165. stat->msgbuf[0] = 0;
  1166. stat->status = 0;
  1167. }
  1168. ///////////////////////////////////////////////////////////////////////////////
  1169. uint GetStatusMYSQL ( MySqlStatus_t *stat, MYSQL *my )
  1170. {
  1171. DASSERT(stat);
  1172. if (my)
  1173. AssignStatusMYSQL(stat,mysql_errno(my),mysql_error(my),0);
  1174. else
  1175. ClearStatusMYSQL(stat);
  1176. return stat->status;
  1177. }
  1178. ///////////////////////////////////////////////////////////////////////////////
  1179. void AssignStatusMYSQL
  1180. (
  1181. MySqlStatus_t *stat, // valid struct
  1182. int stat_code, // error status to assign
  1183. ccp message, // NULL or pointer to message
  1184. int copy_mode // 0:copy message, 1:use ptr, 2:use+free ptr
  1185. )
  1186. {
  1187. DASSERT(stat);
  1188. ClearStatusMYSQL(stat);
  1189. stat->status = stat_code;
  1190. if (message)
  1191. {
  1192. if ( copy_mode > 0 )
  1193. {
  1194. stat->message = message;
  1195. stat->alloced = copy_mode > 1;
  1196. }
  1197. else
  1198. {
  1199. const uint len = strlen(message);
  1200. if ( len < sizeof(stat->msgbuf) )
  1201. {
  1202. memcpy(stat->msgbuf,message,len+1);
  1203. stat->message = stat->msgbuf;
  1204. stat->alloced = false;
  1205. }
  1206. else
  1207. {
  1208. stat->message = MEMDUP(message,len);
  1209. stat->alloced = true;
  1210. }
  1211. }
  1212. }
  1213. }
  1214. ///////////////////////////////////////////////////////////////////////////////
  1215. void CopyStatusMYSQL
  1216. (
  1217. MySqlStatus_t *dest, // NULL or initialized status
  1218. bool init_dest, // true: initialize 'dest'
  1219. const MySqlStatus_t *src // NULL (clear dest)
  1220. // or initialized status (assign to dest)
  1221. )
  1222. {
  1223. if (dest)
  1224. {
  1225. if (init_dest)
  1226. InitializeStatusMYSQL(dest);
  1227. if ( dest != src )
  1228. {
  1229. if (src)
  1230. AssignStatusMYSQL(dest,src->status,src->message,0);
  1231. else
  1232. ClearStatusMYSQL(dest);
  1233. }
  1234. }
  1235. }
  1236. ///////////////////////////////////////////////////////////////////////////////
  1237. void MoveStatusMYSQL
  1238. (
  1239. MySqlStatus_t *dest, // NULL or initialized status
  1240. bool init_dest, // true: initialize 'dest'
  1241. MySqlStatus_t *src // NULL (clear dest)
  1242. // or initialized status (move to dest)
  1243. )
  1244. {
  1245. if ( dest != src )
  1246. {
  1247. if (dest)
  1248. {
  1249. if (init_dest)
  1250. InitializeStatusMYSQL(dest);
  1251. else
  1252. ClearStatusMYSQL(dest);
  1253. if (src)
  1254. {
  1255. memcpy(dest,src,sizeof(*dest));
  1256. if ( src->message == src->msgbuf )
  1257. dest->message = dest->msgbuf;
  1258. memset(src,0,sizeof(*src));
  1259. }
  1260. }
  1261. else if (src)
  1262. ClearStatusMYSQL(src);
  1263. }
  1264. }
  1265. ///////////////////////////////////////////////////////////////////////////////
  1266. void PrintStatusMYSQL
  1267. (
  1268. MySqlStatus_t *stat, // valid struct
  1269. int stat_code, // error status to assign
  1270. ccp format, // format string for vsnprintf()
  1271. ... // parameters for 'format'
  1272. )
  1273. {
  1274. DASSERT(stat);
  1275. DASSERT(format);
  1276. char buf[10000];
  1277. va_list arg;
  1278. va_start(arg,format);
  1279. int len = vsnprintf(buf,sizeof(buf),format,arg);
  1280. va_end(arg);
  1281. if ( len < sizeof(buf) )
  1282. AssignStatusMYSQL(stat,stat_code,buf,0);
  1283. else
  1284. {
  1285. //--- buffer too small, use dynamic memory
  1286. noPRINT("PrintQueryMYSQL() -> MALLOC(%u)\n",stat+1);
  1287. char *dest = MALLOC(len+1);
  1288. va_start(arg,format);
  1289. len = vsnprintf(dest,len+1,format,arg);
  1290. va_end(arg);
  1291. AssignStatusMYSQL(stat,stat_code,dest,2);
  1292. }
  1293. }
  1294. //
  1295. ///////////////////////////////////////////////////////////////////////////////
  1296. /////////////// MySqlServerStats_t ///////////////
  1297. ///////////////////////////////////////////////////////////////////////////////
  1298. enumError GetMySqlServerStats ( MySql_t *my, MySqlServerStats_t *stat )
  1299. {
  1300. DASSERT(my);
  1301. DASSERT(stat);
  1302. InitializeMySqlServerStats(stat);
  1303. static const char query[]
  1304. = "show status where variable_name in"
  1305. " ('Uptime','Max_used_connections','Connections','Queries')";
  1306. enumError err
  1307. = DoQueryMYSQL(my,MYLL_QUERY_ON_ERROR,query,sizeof(query)-1);
  1308. if (!err)
  1309. {
  1310. MySqlResult_t *res = UseResultMYSQL(my,false);
  1311. if (res)
  1312. {
  1313. for(;;)
  1314. {
  1315. mem_t *row = GetNextRowMYSQL(res);
  1316. if (!row)
  1317. break;
  1318. //printf("|%s|%s|\n",row[0].ptr,row[1].ptr);
  1319. switch(row[0].ptr[0])
  1320. {
  1321. case 'C':
  1322. if (!strcmp(row[0].ptr,"Connections"))
  1323. stat->connections = strtoull(row[1].ptr,0,10);
  1324. break;
  1325. case 'M':
  1326. if (!strcmp(row[0].ptr,"Max_used_connections"))
  1327. stat->max_connections = strtoull(row[1].ptr,0,10);
  1328. break;
  1329. case 'Q':
  1330. if (!strcmp(row[0].ptr,"Queries"))
  1331. stat->queries = strtoull(row[1].ptr,0,10);
  1332. break;
  1333. case 'U':
  1334. if (!strcmp(row[0].ptr,"Uptime"))
  1335. stat->uptime = strtoull(row[1].ptr,0,10);
  1336. break;
  1337. }
  1338. }
  1339. FreeResultMYSQL(res);
  1340. }
  1341. }
  1342. return err;
  1343. }
  1344. ///////////////////////////////////////////////////////////////////////////////
  1345. MySqlServerStats_t * Add3MySqlServerStats
  1346. (
  1347. // return dest
  1348. // calculate: dest = src1 + src2
  1349. MySqlServerStats_t *dest, // NULL or destination (maybe same as source)
  1350. const MySqlServerStats_t *src1, // NULL or first source
  1351. const MySqlServerStats_t *src2 // NULL or second source
  1352. )
  1353. {
  1354. if (dest)
  1355. {
  1356. if (!src1)
  1357. {
  1358. if (src2)
  1359. memcpy(dest,src2,sizeof(*dest));
  1360. else
  1361. InitializeMySqlServerStats(dest);
  1362. }
  1363. else if (!src2)
  1364. {
  1365. DASSERT(src1);
  1366. memcpy(dest,src1,sizeof(*dest));
  1367. }
  1368. else
  1369. {
  1370. DASSERT(src1);
  1371. DASSERT(src2);
  1372. dest->max_connections = src1->max_connections > src2->max_connections
  1373. ? src1->max_connections : src2->max_connections;
  1374. dest->uptime = src1->uptime + src2->uptime;
  1375. dest->connections = src1->connections + src2->connections;
  1376. dest->queries = src1->queries + src2->queries;
  1377. }
  1378. }
  1379. return dest;
  1380. }
  1381. ///////////////////////////////////////////////////////////////////////////////
  1382. MySqlServerStats_t * Sub3MySqlServerStats
  1383. (
  1384. // return dest
  1385. // calculate: dest = src1 - src2
  1386. MySqlServerStats_t *dest, // NULL or destination (maybe same as source)
  1387. const MySqlServerStats_t *src1, // NULL or first source
  1388. const MySqlServerStats_t *src2 // NULL or second source
  1389. )
  1390. {
  1391. if (dest)
  1392. {
  1393. if (!src1)
  1394. {
  1395. if (src2)
  1396. {
  1397. MySqlServerStats_t temp;
  1398. InitializeMySqlServerStats(&temp);
  1399. Sub3MySqlServerStats(dest,&temp,src2);
  1400. }
  1401. else
  1402. InitializeMySqlServerStats(dest);
  1403. }
  1404. else if (!src2)
  1405. {
  1406. DASSERT(src1);
  1407. memcpy(dest,src1,sizeof(*dest));
  1408. }
  1409. else
  1410. {
  1411. DASSERT(src1);
  1412. DASSERT(src2);
  1413. dest->max_connections = src1->max_connections;
  1414. dest->uptime = src1->uptime - src2->uptime;
  1415. dest->connections = src1->connections - src2->connections;
  1416. dest->queries = src1->queries - src2->queries;
  1417. }
  1418. }
  1419. return dest;
  1420. }
  1421. ///////////////////////////////////////////////////////////////////////////////
  1422. MySqlServerStats_t * Max2MySqlServerStats
  1423. (
  1424. // return dest
  1425. // calculate: dest := max(dest,src)
  1426. MySqlServerStats_t *dest, // NULL or destination (maybe same as source)
  1427. const MySqlServerStats_t *src // NULL or source
  1428. )
  1429. {
  1430. if ( src && dest )
  1431. {
  1432. if ( dest->max_connections < src->max_connections )
  1433. dest->max_connections = src->max_connections;
  1434. if ( dest->uptime < src->uptime )
  1435. dest->uptime = src->uptime;
  1436. if ( dest->connections < src->connections )
  1437. dest->connections = src->connections;
  1438. if ( dest->queries < src->queries )
  1439. dest->queries = src->queries;
  1440. }
  1441. return dest;
  1442. }
  1443. //
  1444. ///////////////////////////////////////////////////////////////////////////////
  1445. /////////////// END ///////////////
  1446. ///////////////////////////////////////////////////////////////////////////////