123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716 |
- /***************************************************************************
- * *
- * _____ ____ *
- * | __ \ / __ \ _ _ _____ *
- * | | \ \ / / \_\ | | | | _ \ *
- * | | \ \| | | | | | |_| | *
- * | | | || | | | | | ___/ *
- * | | / /| | __ | | | | _ \ *
- * | |__/ / \ \__/ / | |___| | |_| | *
- * |_____/ \____/ |_____|_|_____/ *
- * *
- * Wiimms source code library *
- * *
- ***************************************************************************
- * *
- * Copyright (c) 2012-2022 by Dirk Clemens <wiimm@wiimm.de> *
- * *
- ***************************************************************************
- * *
- * This library is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This library is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * See file gpl-2.0.txt or http://www.gnu.org/licenses/gpl-2.0.txt *
- * *
- ***************************************************************************/
- #define _GNU_SOURCE 1
- #include <string.h>
- #include <stddef.h>
- #include <mysql/mysql.h>
- #include <mysql/errmsg.h>
- #include "dclib-mysql.h"
- #include "dclib-file.h"
- #include "dclib-network.h"
- // http://dev.mysql.com/doc/refman/5.1/en/c-api-functions.html
- //
- ///////////////////////////////////////////////////////////////////////////////
- /////////////// global vars ///////////////
- ///////////////////////////////////////////////////////////////////////////////
- UsageDuration_t mysql_query_usage = { .par.used = 0, .par.enabled = true };
- const UsageCtrl_t mysql_query_usage_ctrl =
- {
- .par = &mysql_query_usage.par,
- .ud = &mysql_query_usage,
- .title = "Database queries",
- .key1 = "DB",
- .key2 = "MYSQL",
- .srt_prefix = "my-q-",
- };
- ///////////////////////////////////////////////////////////////////////////////
- const SaveRestoreTab_t SRT_Mysql[] =
- {
- #undef SRT_NAME
- #define SRT_NAME MySql_t
- DEF_SRT_COMMENT("mysql stats"),
- DEF_SRT_SEPARATOR(),
- DEF_SRT_MODE_ADD(),
- DEF_SRT_UINT( total_connect_count, "mystat-connect" ),
- DEF_SRT_UINT( total_query_count, "mystat-query-c" ),
- DEF_SRT_UINT( total_query_size, "mystat-query-s" ),
- DEF_SRT_UINT( total_result_count, "mystat-result" ),
- DEF_SRT_UINT( total_row_count, "mystat-row" ),
- DEF_SRT_UINT( total_field_count, "mystat-field-c" ),
- DEF_SRT_UINT( total_field_size, "mystat-field-s" ),
- DEF_SRT_SEPARATOR(),
- DEF_SRT_TERM()
- };
- //
- ///////////////////////////////////////////////////////////////////////////////
- /////////////// watch long queries ///////////////
- ///////////////////////////////////////////////////////////////////////////////
- static ccp wq_fname = 0; // NULL or opened file
- static LogFile_t wq_log = {0}; // log data
- static bool wq_failed = false; // true, if fopen() faild => don't try again
- static u_nsec_t wq_nsec = M1(wq_nsec); // >0: log queries that need ≥# nsec
- static uint wq_size = M1(wq_size); // >0: log queries with ≥# bytes
- ///////////////////////////////////////////////////////////////////////////////
- void SetupQueryLogMYSQL
- (
- ccp fname, // filename of log file, openend with mode "a"
- ccp tag, // identification of the tool for shared log files
- u_nsec_t nsec, // >0: log queries that need e# nsec
- uint size // >0: log queries that are longer e# bytes
- )
- {
- CloseQueryLogMYSQL();
- wq_fname = fname;
- wq_failed = false;
- wq_nsec = nsec ? nsec : M1(wq_nsec);
- wq_size = size ? size : M1(wq_size);
- wq_log.tag = MemByString0(tag);
- wq_log.ts_mode = TSM_MSEC;
- wq_log.flush = true;
- }
- ///////////////////////////////////////////////////////////////////////////////
- void CloseQueryLogMYSQL()
- {
- if (wq_log.log)
- {
- fclose(wq_log.log);
- wq_log.log = 0;
- }
- }
- ///////////////////////////////////////////////////////////////////////////////
- LogFile_t * OpenQueryLogMYSQL()
- {
- if (!wq_log.log)
- {
- if ( wq_failed || !wq_fname || !*wq_fname )
- {
- wq_failed = true;
- return 0;
- }
- wq_log.log = fopen(wq_fname,"ab");
- if (!wq_log.log)
- {
- wq_failed = true;
- return 0;
- }
- }
- return &wq_log;
- }
- //
- ///////////////////////////////////////////////////////////////////////////////
- /////////////// struct MySql_t ///////////////
- ///////////////////////////////////////////////////////////////////////////////
- // management
- void InitializeMYSQL ( MySql_t *my )
- {
- #if DEBUG
- static uint done = 0;
- if (!done)
- {
- done++;
- TRACE("- MYSQL\n");
- TRACE_SIZEOF(MySql_t);
- TRACE_SIZEOF(MySqlResult_t);
- TRACE_SIZEOF(MySqlStatus_t);
- TRACE_SIZEOF(st_mysql);
- TRACE_SIZEOF(st_mysql_res);
- TRACE_SIZEOF(st_mysql_field);
- }
- #endif
- DASSERT(my);
- memset(my,0,sizeof(*my));
- my->auto_reconnect = true;
- my->prefix = EmptyString;
- InitializeStatusMYSQL(&my->status);
- AddToUsageMgr(&mysql_query_usage_ctrl);
- }
- ///////////////////////////////////////////////////////////////////////////////
- void ResetMYSQL ( MySql_t *my )
- {
- DASSERT(my);
- CloseMYSQL(my);
- FREE((char*)my->server);
- FREE((char*)my->user);
- FREE((char*)my->password);
- FREE((char*)my->database);
- FreeString(my->prefix);
- InitializeMYSQL(my);
- }
- ///////////////////////////////////////////////////////////////////////////////
- enumError OpenMYSQL ( MySql_t *my, uint loglevel )
- {
- DASSERT(my);
- ClearStatusMYSQL(&my->status);
- if (my->mysql)
- return ERR_OK; // already connected
- if ( !my || !my->server )
- {
- if ( loglevel >= MYLL_ERROR )
- ERROR0(ERR_MISSING_PARAM,"No MySql server defined.\n");
- return ERR_MISSING_PARAM;
- }
- NetworkHost_t host;
- ResolveHost(&host,true,my->server,MYSQL_DEFAULT_PORT,false,true);
- PRINT("MYSQL CONNECT: %s:%u -> %s\n",
- host.name, host.port, PrintIP4(0,0,host.ip4,host.port) );
- static bool lib_init_done = false;
- if (!lib_init_done)
- {
- noPRINT("mysql_library_init()\n");
- if (mysql_library_init(0,NULL,NULL))
- {
- if ( loglevel >= MYLL_ERROR )
- ERROR0(ERR_DATABASE,"Can't initialize MySql library.\n");
- return ERR_DATABASE;
- }
- lib_init_done = true;
- }
- my->mysql = mysql_init(NULL);
- //HEXDUMP16(0,0,my->mysql,sizeof(*my->mysql));
- if (!my->mysql)
- {
- if ( loglevel >= MYLL_ERROR )
- ERROR0(ERR_DATABASE,"Can't initialize MySql data.\n");
- ResetHost(&host);
- return ERR_DATABASE;
- }
- if (my->auto_reconnect)
- {
- my_bool reconnect = 1;
- mysql_options(my->mysql,MYSQL_OPT_RECONNECT,&reconnect);
- }
- noPRINT("connect(%p,%s,%s,%s,%s,%u,,)\n",
- my->mysql, host.name, my->user, my->password, my->database, host.port );
- MYSQL *stat = mysql_real_connect ( my->mysql, host.name,
- my->user, my->password, my->database,
- host.port, NULL, 0 );
- if (!stat)
- {
- GetStatusMYSQL(&my->status,my->mysql);
- if ( loglevel >= MYLL_ERROR )
- ERROR0(ERR_CANT_CONNECT,"Can't connect to %s:\n-> %s\n",
- PrintIP4(0,0,host.ip4,host.port),my->status.message);
- ResetHost(&host);
- mysql_close(my->mysql);
- my->mysql = 0;
- return ERR_CANT_CONNECT;
- }
- mysql_set_character_set(my->mysql,"utf8mb4");
- my->total_connect_count++;
- ResetHost(&host);
- return ERR_OK;
- }
- ///////////////////////////////////////////////////////////////////////////////
- void CloseMYSQL ( MySql_t *my )
- {
- DASSERT(my);
- //--- close results
- FreeResultListMYSQL(my->first_result);
- my->first_result = 0;
- FreeResultListMYSQL(my->pool_result);
- my->pool_result = 0;
- //--- close database
- if (my->mysql)
- {
- mysql_close(my->mysql);
- my->mysql = 0;
- }
- //--- reset status
- ClearStatusMYSQL(&my->status);
- }
- ///////////////////////////////////////////////////////////////////////////////
- void DefineDatabase
- (
- MySql_t *my, // valid struct
- ccp server, // NULL or server name
- ccp user, // NULL or user name
- ccp password, // NULL or user password
- ccp database // NULL or name of database
- )
- {
- DASSERT(my);
- CloseMYSQL(my);
- if (server)
- {
- FREE((char*)my->server);
- my->server = STRDUP(server);
- }
- if (user)
- {
- FREE((char*)my->user);
- my->user = STRDUP(user);
- }
- if (password)
- {
- FREE((char*)my->password);
- my->password = STRDUP(password);
- }
- if (database)
- {
- FREE((char*)my->database);
- my->database = STRDUP(database);
- }
- FreeString(my->prefix);
- my->prefix = EmptyString;
- }
- ///////////////////////////////////////////////////////////////////////////////
- void DefineDatabasePrefix
- (
- MySql_t *my, // valid struct
- ccp prefix // NULL or default prefix, only for external usage
- )
- {
- DASSERT(my);
- FreeString(my->prefix);
- my->prefix = prefix && *prefix ? STRDUP(prefix) : EmptyString;
- }
- ///////////////////////////////////////////////////////////////////////////////
- static enumError CheckOpenMYSQL ( MySql_t *my, uint loglevel )
- {
- if (AutoOpenMYSQL(my,loglevel))
- return ERR_OK;
- if ( loglevel >= MYLL_ERROR )
- ERROR0(ERR_SEMANTIC,"No database connected.\n");
- return ERR_SEMANTIC;
- }
- //
- ///////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////
- // queries
- static void update_query_duration
- ( MySql_t *my, u_nsec_t start_time, ccp query, uint qlen )
- {
- DASSERT(my);
- const u_usec_t dur_nsec = GetTimerNSec() - start_time;
- my->last_duration_usec = dur_nsec / NSEC_PER_USEC;
- if ( my->max_duration_usec < my->last_duration_usec )
- my->max_duration_usec = my->last_duration_usec;
- my->total_duration_usec += my->last_duration_usec;
- UpdateUsageDurationIncrement(&mysql_query_usage,dur_nsec);
- if ( dur_nsec >= wq_nsec || qlen >= wq_size )
- {
- LogFile_t *lf = OpenQueryLogMYSQL();
- if (lf)
- {
- char buf[2000], *dest = buf;
- bool have_space = false;
- while ( *query && dest < buf+sizeof(buf)-2 )
- {
- const uchar ch = *query++;
- if ( ch > ' ' )
- {
- if (have_space)
- {
- have_space = false;
- *dest++ = ' ';
- }
- *dest++ = ch;
- }
- else if ( dest > buf )
- have_space = true;
- }
- *dest = 0;
- PrintLogFile(lf,"%5u %s : %s\n",
- qlen,
- PrintTimerNSec6(0,0,dur_nsec,DC_SFORM_ALIGN|DC_SFORM_DASH),
- buf );
- }
- }
- }
- //-----------------------------------------------------------------------------
- enumError DoQueryMYSQL
- (
- MySql_t *my, // valid struct
- LogLevelMYSQL loglevel, // log level for mysql errors and queries
- ccp query, // query string
- int query_length // length of 'query', -1 if unknown
- )
- {
- DASSERT(my);
- DASSERT(query);
- const u_nsec_t start_time = GetTimerNSec();
- enumError err = CheckOpenMYSQL(my,loglevel);
- if (err)
- return err;
- if ( query_length < 0 )
- query_length = strlen(query);
- my->total_query_count++;
- my->total_query_size += query_length;
- if (mysql_real_query(my->mysql,query,query_length))
- {
- TRACE("QUERY: %.*s\n",query_length,query);
- my->field_count = 0;
- GetStatusMYSQL(&my->status,my->mysql);
- bool fail = true;
- if ( my->status.status == CR_SERVER_GONE_ERROR && my->auto_reconnect )
- {
- MySqlStatus_t save;
- MoveStatusMYSQL(&save,true,&my->status);
- CloseMYSQL(my);
- if ( OpenMYSQL(my,loglevel) || mysql_real_query(my->mysql,query,query_length) )
- MoveStatusMYSQL(&my->status,false,&save);
- else
- {
- ClearStatusMYSQL(&save);
- fail = false;
- }
- }
- if (fail)
- {
- if ( loglevel >= MYLL_QUERY_ON_ERROR )
- ERROR0(ERR_DATABASE,"%s (#%d)\n--QUERY--\n%.*s\n",
- my->status.message, my->status.status,
- query_length, query );
- else if ( loglevel >= MYLL_ERROR )
- ERROR0(ERR_DATABASE,"%s (#%d)\n",
- my->status.message, my->status.status );
- update_query_duration(my,start_time,query,query_length);
- return ERR_DATABASE;
- }
- }
- if ( loglevel >= MYLL_QUERY_ALWAYS )
- ERROR0(ERR_OK,"%.*s\n", query_length, query );
- my->field_count = mysql_field_count(my->mysql);
- ClearStatusMYSQL(&my->status);
- update_query_duration(my,start_time,query,query_length);
- return ERR_OK;
- }
- ///////////////////////////////////////////////////////////////////////////////
- enumError PrintArgQueryMYSQL
- (
- MySql_t *my, // valid struct
- LogLevelMYSQL loglevel, // log level for mysql errors and queries
- ccp format, // format string for vsnprintf()
- va_list arg // parameters for 'format'
- )
- {
- DASSERT(my);
- DASSERT(format);
- char buf[10000];
- va_list arg2;
- va_copy(arg2,arg);
- int stat = vsnprintf(buf,sizeof(buf),format,arg2);
- va_end(arg2);
- if ( stat < sizeof(buf) )
- return DoQueryMYSQL(my,loglevel,buf,stat);
- //--- buffer too small, use dynamic memory
- noPRINT("PrintQueryMYSQL() -> MALLOC(%u)\n",stat+1);
- char *dest = MALLOC(stat+1);
- stat = vsnprintf(dest,stat+1,format,arg);
- const enumError err = DoQueryMYSQL(my,loglevel,dest,stat);
- FREE(dest);
- return err;
- }
- ///////////////////////////////////////////////////////////////////////////////
- enumError PrintQueryMYSQL
- (
- MySql_t *my, // valid struct
- LogLevelMYSQL loglevel, // log level for mysql errors and queries
- ccp format, // format string for vsnprintf()
- ... // parameters for 'format'
- )
- {
- DASSERT(my);
- DASSERT(format);
- va_list arg;
- va_start(arg,format);
- enumError err = PrintArgQueryMYSQL(my,loglevel,format,arg);
- va_end(arg);
- return err;
- }
- //
- ///////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////
- // support of multi queries
- mem_t GetFirstQuery ( ccp src, int src_len )
- {
- if (!src)
- {
- mem_t res = {0,0};
- return res;
- }
- ccp ptr = src;
- ccp end = ptr + ( src_len < 0 ? strlen(src) : src_len );
- //--- skip all leading blanks, controls and semicolons
- while ( ptr < end && ( *ptr >= 0 && *ptr <= ' ' || *ptr == ';' ) )
- ptr++;
- if ( ptr == end )
- {
- mem_t res = {ptr,0};
- return res;
- }
- ccp start = ptr;
- while ( ptr < end )
- {
- const char ch = *ptr++;
- if ( ch == ';' )
- {
- mem_t res = {start,ptr-start-1};
- return res;
- }
- if ( ch == '\\' && ptr < end )
- ptr++;
- else if ( ch == '\'' || ch == '\"' )
- {
- while ( ptr < end )
- {
- const char ch2 = *ptr++;
- if ( ch2 == '\\' && ptr < end )
- ptr++;
- else if ( ch2 == ch )
- break;
- }
- }
- }
- mem_t res = {start,ptr-start};
- return res;
- }
- ///////////////////////////////////////////////////////////////////////////////
- enumError DoMultiQueryMYSQL
- (
- MySql_t *my, // valid struct
- LogLevelMYSQL loglevel, // log level for mysql errors and queries
- ccp query, // query string
- int query_length // length of 'query', -1 if unknown
- )
- {
- DASSERT(my);
- DASSERT(query);
- mem_t q;
- q.ptr = query;
- q.len = query_length < 0 ? strlen(query) : query_length;
- for(;;)
- {
- mem_t q1 = GetFirstQuery(q.ptr,q.len);
- if (!q1.len)
- break;
- const enumError err = DoQueryMYSQL(my,loglevel,q1.ptr,q1.len);
- if (err)
- return err;
- q = BehindMem(q,q1.ptr+q1.len);
- }
- return ERR_OK;
- }
- ///////////////////////////////////////////////////////////////////////////////
- enumError PrintMultiQueryMYSQL
- (
- MySql_t *my, // valid struct
- LogLevelMYSQL loglevel, // log level for mysql errors and queries
- ccp format, // format string for vsnprintf()
- ... // parameters for 'format'
- )
- {
- DASSERT(my);
- DASSERT(format);
- char buf[10000];
- va_list arg;
- va_start(arg,format);
- int stat = vsnprintf(buf,sizeof(buf),format,arg);
- va_end(arg);
- if ( stat < sizeof(buf) )
- return DoMultiQueryMYSQL(my,loglevel,buf,stat);
- //--- buffer too small, use dynamic memory
- noPRINT("PrintQueryMYSQL() -> MALLOC(%u)\n",stat+1);
- char *dest = MALLOC(stat+1);
- va_start(arg,format);
- stat = vsnprintf(dest,stat+1,format,arg);
- va_end(arg);
- const enumError err = DoMultiQueryMYSQL(my,loglevel,dest,stat);
- FREE(dest);
- return err;
- }
- //
- ///////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////
- // temp buffer support
- mem_t CopyMemMYSQL ( MySql_t * my, mem_t * src ) // 'src' may be NULL
- {
- if ( src && src->len > 0 )
- {
- if ( src->len < sizeof(my->tempbuf) && !my->tempbuf_used )
- {
- noPRINT("MYSQL: use tempbuf(%u)\n",src->len);
- memcpy(my->tempbuf,src->ptr,src->len);
- my->tempbuf[src->len] = 0;
- my->tempbuf_used = true;
- mem_t res = { my->tempbuf, src->len };
- return res;
- }
- return DupMem(*src);
- }
- mem_t res = {NULL,0};
- return res;
- }
- ///////////////////////////////////////////////////////////////////////////////
- void FreeMemMYSQL ( MySql_t * my, mem_t mem )
- {
- DASSERT(my);
- if ( mem.ptr == my->tempbuf )
- {
- noPRINT("MYSQL: free tempbuf\n");
- my->tempbuf_used = false;
- }
- else
- FREE((char*)mem.ptr);
- }
- //
- ///////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////
- // fetch single value as result of a query
- mem_t FetchScalarMYSQL // FREE the result!
- (
- MySql_t *my, // valid struct
- LogLevelMYSQL loglevel // log level for mysql errors and queries
- )
- {
- DASSERT(my);
- mem_t ret = {NULL,0};
- MySqlResult_t *res = UseResultMYSQL(my,loglevel);
- if (res)
- {
- ret = CopyMemMYSQL(my,GetNextRowMYSQL(res));
- while (GetNextRowMYSQL(res)) // get all rows
- ;
- FreeResultMYSQL(res);
- }
- return ret;
- }
- ///////////////////////////////////////////////////////////////////////////////
- s64 FetchIntMYSQL
- (
- MySql_t *my, // valid struct
- LogLevelMYSQL loglevel, // log level for mysql errors and queries
- bool allow_trail, // allow additional chars behind number
- s64 return_default // return this value on non existent result
- )
- {
- DASSERT(my);
- mem_t res = FetchScalarMYSQL(my,loglevel);
- if (!res.len)
- return return_default;
- char *end;
- const s64 val = strtoll(res.ptr,&end,10);
- FreeMemMYSQL(my,res);
- return allow_trail || end == res.ptr + res.len ? val : return_default;
- }
- ///////////////////////////////////////////////////////////////////////////////
- u64 FetchUIntMYSQL
- (
- MySql_t *my, // valid struct
- LogLevelMYSQL loglevel, // log level for mysql errors and queries
- bool allow_trail, // allow additional chars behind number
- u64 return_default // return this value on non existent result
- )
- {
- DASSERT(my);
- mem_t res = FetchScalarMYSQL(my,loglevel);
- if (!res.len)
- return return_default;
- char *end;
- const u64 val = strtoull(res.ptr,&end,10);
- FreeMemMYSQL(my,res);
- return allow_trail || end == res.ptr + res.len ? val : return_default;
- }
- //
- ///////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////
- // print query & fetch single value as result
- mem_t PrintArgFetchScalarMYSQL
- (
- // if res.len>0: FREE the result using FreeMemMYSQL(my,mem)
- MySql_t *my, // valid struct
- LogLevelMYSQL loglevel, // log level for mysql errors and queries
- ccp format, // format string for vsnprintf()
- va_list arg // parameters for 'format'
- )
- {
- DASSERT(my);
- DASSERT(format);
- mem_t ret = {NULL,0};
- if (!PrintArgQueryMYSQL(my,loglevel,format,arg))
- {
- MySqlResult_t *res = UseResultMYSQL(my,loglevel);
- if (res)
- {
- ret = CopyMemMYSQL(my,GetNextRowMYSQL(res));
- while (GetNextRowMYSQL(res)) // get all rows
- ;
- FreeResultMYSQL(res);
- }
- }
- return ret;
- }
- ///////////////////////////////////////////////////////////////////////////////
- mem_t PrintFetchScalarMYSQL
- (
- // if res.len>0: FREE the result using FreeMemMYSQL(my,mem)
- MySql_t *my, // valid struct
- LogLevelMYSQL loglevel, // log level for mysql errors and queries
- ccp format, // format string for vsnprintf()
- ... // parameters for 'format'
- )
- {
- DASSERT(my);
- DASSERT(format);
- va_list arg;
- va_start(arg,format);
- mem_t res = PrintArgFetchScalarMYSQL(my,loglevel,format,arg);
- va_end(arg);
- return res;
- }
- ///////////////////////////////////////////////////////////////////////////////
- s64 PrintFetchIntMYSQL
- (
- MySql_t *my, // valid struct
- LogLevelMYSQL loglevel, // log level for mysql errors and queries
- bool allow_trail, // allow additional chars behind number
- s64 return_default, // return this value on non existent result
- ccp format, // format string for vsnprintf()
- ... // parameters for 'format'
- )
- {
- DASSERT(my);
- DASSERT(format);
- va_list arg;
- va_start(arg,format);
- mem_t res = PrintArgFetchScalarMYSQL(my,loglevel,format,arg);
- va_end(arg);
- if (!res.len)
- return return_default;
- char *end;
- const s64 val = strtoll(res.ptr,&end,10);
- FreeMemMYSQL(my,res);
- return allow_trail || end == res.ptr + res.len ? val : return_default;
- }
- ///////////////////////////////////////////////////////////////////////////////
- u64 PrintFetchUIntMYSQL
- (
- MySql_t *my, // valid struct
- LogLevelMYSQL loglevel, // log level for mysql errors and queries
- bool allow_trail, // allow additional chars behind number
- u64 return_default, // return this value on non existent result
- ccp format, // format string for vsnprintf()
- ... // parameters for 'format'
- )
- {
- DASSERT(my);
- DASSERT(format);
- va_list arg;
- va_start(arg,format);
- mem_t res = PrintArgFetchScalarMYSQL(my,loglevel,format,arg);
- va_end(arg);
- if (!res.len)
- return return_default;
- char *end;
- const u64 val = strtoull(res.ptr,&end,10);
- FreeMemMYSQL(my,res);
- return allow_trail || end == res.ptr + res.len ? val : return_default;
- }
- //
- ///////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////
- // fetch single row
- void * FetchSingleRowN
- (
- // returns NULL on error or emtpy result,
- // or a temporary buffer => call FREE(result)
- // following rows will be skipped
- MySql_t *my, // valid struct
- LogLevelMYSQL loglevel, // log level for mysql errors and queries
- mem_t *dest, // dest buffer, unused elements are set to {0,0}
- uint n_dest // number of elements in 'dest'
- )
- {
- DASSERT(my);
- DASSERT( dest || !n_dest );
- memset(dest,0,sizeof(*dest)*n_dest);
- char *buf = 0;
- MySqlResult_t *res = UseResultMYSQL(my,loglevel);
- if (res)
- {
- mem_t *row = GetNextRowMYSQL(res);
- if (row)
- {
- if ( n_dest > res->field_count )
- n_dest = res->field_count;
- //--- count memory usage and alloc buffer
- uint i, need = 0;
- for ( i = 0; i < n_dest; i++ )
- if ( row[i].len )
- need += row[i].len + 1;
- //--- get row data
- buf = MALLOC(need);
- char *ptr = buf;
- for ( i = 0; i < n_dest; i++, row++, dest++ )
- {
- if ( row->len )
- {
- dest->ptr = ptr;
- memcpy(ptr,row->ptr,row->len);
- dest->len = row->len;
- ptr += row->len;
- *ptr++ = 0;
- DASSERT( ptr <= buf+need );
- }
- }
- DASSERT( ptr == buf+need );
- //--- get and ignore all remaining rows
- while (GetNextRowMYSQL(res))
- ;
- }
- FreeResultMYSQL(res);
- }
- return buf;
- }
- ///////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////
- int FetchSingleRowList
- (
- // returns -1 on error, 0 on empty result or the number of retrieved field
- // following rows will be skipped
- MySql_t *my, // valid struct
- LogLevelMYSQL loglevel, // log level for mysql errors and queries
- mem_list_t *dest, // destination list
- bool init_dest, // true: initialize 'dest'
- bool replace_null // true: replace NULL by EmptyString
- )
- {
- DASSERT(my);
- DASSERT(dest);
- if (init_dest)
- InitializeMemList(dest);
- dest->used = 0;
- int stat = -1;
- MySqlResult_t *res = UseResultMYSQL(my,loglevel);
- if (res)
- {
- stat = 0;
- mem_t *row = GetNextRowMYSQL(res);
- if (row)
- {
- stat = res->field_count;
- AssignMemListN(dest,row,stat,replace_null?3:0);
- //--- get and ignore all remaining rows
- while (GetNextRowMYSQL(res))
- ;
- }
- FreeResultMYSQL(res);
- }
- return stat;
- }
- //
- ///////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////
- // count tables and columns
- int CountTablesMYSQL
- (
- MySql_t *my, // valid DB connection
- ccp table, // like "table"; if NULL|EMPTY: count tables
- ccp database // database name; if NULL|EMPTY: use default DB
- )
- {
- DASSERT(my);
- int stat = -1;
- mem_t db = EscapeStringMYSQL(my, database && *database ? database : my->database );
- mem_t tab = EscapeStringMYSQL(my, table && *table ? table : "%" );
- stat = PrintFetchIntMYSQL(my,MYLL_QUERY_ON_ERROR,false,-1,
- "SELECT COUNT(DISTINCT TABLE_NAME) FROM information_schema.COLUMNS\n"
- "WHERE TABLE_SCHEMA = \"%s\" && TABLE_NAME like \"%s\"\n",
- db.ptr, tab.ptr );
- FreeString(tab.ptr);
- FreeString(db.ptr);
- return stat;
- }
- ///////////////////////////////////////////////////////////////////////////////
- int CountColumnsMYSQL
- (
- MySql_t *my, // valid DB connection
- ccp column, // column name; if NULL|EMPTY: count columns
- ccp table, // like "table"; if NULL|EMPTY: all tables
- ccp database // database name; if NULL|EMPTY: use default DB
- )
- {
- DASSERT(my);
- int stat = -1;
- mem_t db = EscapeStringMYSQL(my, database && *database ? database : my->database );
- mem_t tab = EscapeStringMYSQL(my, table && *table ? table : "%" );
- if ( column && *column )
- {
- mem_t col = EscapeStringMYSQL(my,column);
- stat = PrintFetchIntMYSQL(my,MYLL_QUERY_ON_ERROR,false,-1,
- "SELECT COUNT(*) FROM information_schema.COLUMNS\n"
- "WHERE TABLE_SCHEMA = \"%s\" && TABLE_NAME like \"%s\""
- " && COLUMN_NAME = \"%s\"\n",
- db.ptr, tab.ptr, col.ptr );
- FreeString(col.ptr);
- }
- else
- {
- stat = PrintFetchIntMYSQL(my,MYLL_QUERY_ON_ERROR,false,-1,
- "SELECT COUNT(*) FROM information_schema.COLUMNS\n"
- "WHERE TABLE_SCHEMA = \"%s\" && TABLE_NAME like \"%s\"\n",
- db.ptr, tab.ptr );
- }
- FreeString(tab.ptr);
- FreeString(db.ptr);
- return stat;
- }
- //
- ///////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////
- // helpers
- mem_t EscapeMYSQL ( MySql_t *my, cvp ptr, int len )
- {
- DASSERT(my);
- if ( len < 0 )
- len = ptr ? strlen(ptr) : 0;
- mem_t res;
- if ( !ptr || !len )
- {
- res.ptr = EmptyString;
- res.len = 0;
- }
- else
- {
- char *buf = MALLOC(2*len+1);
- res.ptr = buf;
- res.len = mysql_real_escape_string(my->mysql,buf,ptr,len);
- }
- return res;
- }
- //-----------------------------------------------------------------------------
- mem_t EscapeMYSQLCirc ( MySql_t *my, cvp ptr, int len )
- {
- DASSERT(my);
- if ( len < 0 )
- len = ptr ? strlen(ptr) : 0;
- mem_t res;
- if ( !ptr || !len )
- {
- res.ptr = EmptyString;
- res.len = 0;
- }
- else if ( len >= CIRC_BUF_MAX_ALLOC )
- {
- // no chance
- res.ptr = 0;
- res.len = 0;
- }
- else
- {
- char buf[2*CIRC_BUF_MAX_ALLOC+10];
- res.len = mysql_real_escape_string(my->mysql,buf,ptr,len);
- if ( res.len < CIRC_BUF_MAX_ALLOC )
- res.ptr = CopyCircBuf(buf,res.len+1);
- else
- {
- res.ptr = 0;
- res.len = 0;
- }
- }
- return res;
- }
- ///////////////////////////////////////////////////////////////////////////////
- mem_t QuoteMYSQL ( MySql_t *my, cvp ptr, int len, bool null_if_empty )
- {
- if ( len < 0 )
- len = ptr ? strlen(ptr) : 0;
- mem_t res;
- if ( !ptr || !len && null_if_empty )
- {
- res.ptr = STRDUP("NULL");
- res.len = 4;
- }
- else if (!len)
- {
- res.ptr = EmptyQuote;
- res.len = 0;
- }
- else
- {
- char *buf = MALLOC(2*len+3);
- res.ptr = buf;
- res.len = mysql_real_escape_string(my->mysql,buf+1,ptr,len) + 2;
- buf[0] = buf[res.len-1] = '"';
- buf[res.len] = 0;
- }
- return res;
- }
- //-----------------------------------------------------------------------------
- mem_t QuoteMYSQLCirc ( MySql_t *my, cvp ptr, int len, bool null_if_empty )
- {
- if ( len < 0 )
- len = ptr ? strlen(ptr) : 0;
- mem_t res;
- if ( !ptr || !len && null_if_empty )
- {
- res.ptr = CopyCircBuf("NULL",5);
- res.len = 4;
- }
- else if (!len)
- {
- res.ptr = EmptyQuote;
- res.len = 2;
- }
- else if ( len >= CIRC_BUF_MAX_ALLOC-2 )
- {
- // no chance
- res.ptr = 0;
- res.len = 0;
- }
- else
- {
- char buf[2*CIRC_BUF_MAX_ALLOC+10];
- res.len = mysql_real_escape_string(my->mysql,buf+1,ptr,len) + 2;
- if ( res.len < CIRC_BUF_MAX_ALLOC )
- {
- buf[0] = buf[res.len-1] = '"';
- buf[res.len] = 0;
- res.ptr = CopyCircBuf(buf,res.len+1);
- }
- else
- {
- res.ptr = 0;
- res.len = 0;
- }
- }
- return res;
- }
- ///////////////////////////////////////////////////////////////////////////////
- TransferStats_t GetStatsMYSQL ( MySql_t *my )
- {
- TransferStats_t tf;
- memset(&tf,0,sizeof(tf));
- if (my)
- {
- tf.conn_count = my->total_connect_count;
- tf.recv_count = my->total_row_count;
- tf.recv_size = my->total_field_size;
- tf.send_count = my->total_query_count;
- tf.send_size = my->total_query_size;
- }
- return tf;
- }
- //
- ///////////////////////////////////////////////////////////////////////////////
- /////////////// struct MySqlResult_t ///////////////
- ///////////////////////////////////////////////////////////////////////////////
- static void InsertResultMYSQL ( MySqlResult_t ** first, MySqlResult_t * res )
- {
- DASSERT(first);
- DASSERT(res);
- DASSERT( res != *first ); // already cleared!
- //--- remove res from previous list
- if (res->prev_result)
- res->prev_result->next_result = res->next_result;
- if (res->next_result)
- res->next_result->prev_result = res->prev_result;
- //--- insert at top of the new list
- res->prev_result = 0;
- res->next_result = *first;
- if (*first)
- (*first)->prev_result = res;
- *first = res;
- FREE(res->row);
- res->row = 0;
- }
- ///////////////////////////////////////////////////////////////////////////////
- MySqlResult_t * UseResultMYSQL ( MySql_t *my, uint loglevel )
- {
- DASSERT(my);
- enumError err = CheckOpenMYSQL(my,loglevel);
- if (err)
- {
- AssignStatusMYSQL(&my->status,1,"No connection to database!",1);
- return NULL;
- }
- MYSQL_RES *myres = mysql_use_result(my->mysql);
- if (!myres)
- {
- GetStatusMYSQL(&my->status,my->mysql);
- if ( loglevel >= MYLL_ERROR )
- ERROR0(ERR_DATABASE,"%s\n",my->status.message);
- return NULL;
- }
- my->total_result_count++;
- MySqlResult_t *res;
- if (my->pool_result)
- {
- res = my->pool_result;
- my->pool_result = res->next_result;
- }
- else
- res = CALLOC(1,sizeof(*res));
- InsertResultMYSQL(&my->first_result,res);
- res->mysql = my;
- res->myres = myres;
- res->loglevel = loglevel;
- res->row_count = 0;
- res->field_count = mysql_num_fields(myres);
- res->row = CALLOC(sizeof(*res->row),res->field_count);
- GetStatusMYSQL(&res->status,my->mysql);
- return res;
- }
- ///////////////////////////////////////////////////////////////////////////////
- void FreeResultMYSQL ( MySqlResult_t * res )
- {
- if (res)
- {
- MySql_t *my = res->mysql;
- DASSERT(my);
- CloseResultMYSQL(res);
- ClearStatusMYSQL(&res->status);
- if ( my->first_result == res )
- my->first_result = res->next_result;
- InsertResultMYSQL(&my->pool_result,res);
- }
- }
- ///////////////////////////////////////////////////////////////////////////////
- void CloseResultMYSQL ( MySqlResult_t * res )
- {
- DASSERT(res);
- if (res->myres)
- {
- mysql_free_result(res->myres);
- res->myres = 0;
- }
- FREE(res->row);
- res->row = 0;
- res->field_count = 0;
- }
- ///////////////////////////////////////////////////////////////////////////////
- void FreeResultListMYSQL ( MySqlResult_t * first )
- {
- while (first)
- {
- MySqlResult_t *res = first;
- first = res->next_result;
- CloseResultMYSQL(res);
- ClearStatusMYSQL(&res->status);
- FREE(res);
- }
- }
- ///////////////////////////////////////////////////////////////////////////////
- mem_t * GetNextRowMYSQL ( MySqlResult_t * res )
- {
- DASSERT(res);
- if ( !res || !res->myres || !res->row )
- return NULL;
- MYSQL_ROW myrow = mysql_fetch_row(res->myres);
- ulong *mylen = mysql_fetch_lengths(res->myres);
- res->myrow = myrow;
- if ( !myrow || !mylen )
- {
- FREE(res->row);
- res->row = 0;
- return NULL;
- }
- res->mysql->total_row_count++;
- mem_t *dest = res->row;
- uint n = res->field_count;
- res->mysql->total_field_count += n;
- while ( n-- > 0 )
- {
- dest->ptr = *myrow++;
- dest->len = *mylen++;
- res->mysql->total_field_size += dest->len;
- noPRINT("%3u: |%.*s|\n",dest->len,dest->len<50?dest->len:50,dest->ptr);
- dest++;
- }
- return res->row;
- }
- //
- ///////////////////////////////////////////////////////////////////////////////
- /////////////// struct MySqlStatus_t ///////////////
- ///////////////////////////////////////////////////////////////////////////////
- void ClearStatusMYSQL ( MySqlStatus_t *stat )
- {
- DASSERT(stat);
- if (stat->alloced)
- {
- FREE((char*)stat->message);
- stat->alloced = false;
- }
- stat->message = stat->msgbuf;
- stat->msgbuf[0] = 0;
- stat->status = 0;
- }
- ///////////////////////////////////////////////////////////////////////////////
- uint GetStatusMYSQL ( MySqlStatus_t *stat, MYSQL *my )
- {
- DASSERT(stat);
- if (my)
- AssignStatusMYSQL(stat,mysql_errno(my),mysql_error(my),0);
- else
- ClearStatusMYSQL(stat);
- return stat->status;
- }
- ///////////////////////////////////////////////////////////////////////////////
- void AssignStatusMYSQL
- (
- MySqlStatus_t *stat, // valid struct
- int stat_code, // error status to assign
- ccp message, // NULL or pointer to message
- int copy_mode // 0:copy message, 1:use ptr, 2:use+free ptr
- )
- {
- DASSERT(stat);
- ClearStatusMYSQL(stat);
- stat->status = stat_code;
- if (message)
- {
- if ( copy_mode > 0 )
- {
- stat->message = message;
- stat->alloced = copy_mode > 1;
- }
- else
- {
- const uint len = strlen(message);
- if ( len < sizeof(stat->msgbuf) )
- {
- memcpy(stat->msgbuf,message,len+1);
- stat->message = stat->msgbuf;
- stat->alloced = false;
- }
- else
- {
- stat->message = MEMDUP(message,len);
- stat->alloced = true;
- }
- }
- }
- }
- ///////////////////////////////////////////////////////////////////////////////
- void CopyStatusMYSQL
- (
- MySqlStatus_t *dest, // NULL or initialized status
- bool init_dest, // true: initialize 'dest'
- const MySqlStatus_t *src // NULL (clear dest)
- // or initialized status (assign to dest)
- )
- {
- if (dest)
- {
- if (init_dest)
- InitializeStatusMYSQL(dest);
- if ( dest != src )
- {
- if (src)
- AssignStatusMYSQL(dest,src->status,src->message,0);
- else
- ClearStatusMYSQL(dest);
- }
- }
- }
- ///////////////////////////////////////////////////////////////////////////////
- void MoveStatusMYSQL
- (
- MySqlStatus_t *dest, // NULL or initialized status
- bool init_dest, // true: initialize 'dest'
- MySqlStatus_t *src // NULL (clear dest)
- // or initialized status (move to dest)
- )
- {
- if ( dest != src )
- {
- if (dest)
- {
- if (init_dest)
- InitializeStatusMYSQL(dest);
- else
- ClearStatusMYSQL(dest);
- if (src)
- {
- memcpy(dest,src,sizeof(*dest));
- if ( src->message == src->msgbuf )
- dest->message = dest->msgbuf;
- memset(src,0,sizeof(*src));
- }
- }
- else if (src)
- ClearStatusMYSQL(src);
- }
- }
- ///////////////////////////////////////////////////////////////////////////////
- void PrintStatusMYSQL
- (
- MySqlStatus_t *stat, // valid struct
- int stat_code, // error status to assign
- ccp format, // format string for vsnprintf()
- ... // parameters for 'format'
- )
- {
- DASSERT(stat);
- DASSERT(format);
- char buf[10000];
- va_list arg;
- va_start(arg,format);
- int len = vsnprintf(buf,sizeof(buf),format,arg);
- va_end(arg);
- if ( len < sizeof(buf) )
- AssignStatusMYSQL(stat,stat_code,buf,0);
- else
- {
- //--- buffer too small, use dynamic memory
- noPRINT("PrintQueryMYSQL() -> MALLOC(%u)\n",stat+1);
- char *dest = MALLOC(len+1);
- va_start(arg,format);
- len = vsnprintf(dest,len+1,format,arg);
- va_end(arg);
- AssignStatusMYSQL(stat,stat_code,dest,2);
- }
- }
- //
- ///////////////////////////////////////////////////////////////////////////////
- /////////////// MySqlServerStats_t ///////////////
- ///////////////////////////////////////////////////////////////////////////////
- enumError GetMySqlServerStats ( MySql_t *my, MySqlServerStats_t *stat )
- {
- DASSERT(my);
- DASSERT(stat);
- InitializeMySqlServerStats(stat);
- static const char query[]
- = "show status where variable_name in"
- " ('Uptime','Max_used_connections','Connections','Queries')";
- enumError err
- = DoQueryMYSQL(my,MYLL_QUERY_ON_ERROR,query,sizeof(query)-1);
- if (!err)
- {
- MySqlResult_t *res = UseResultMYSQL(my,false);
- if (res)
- {
- for(;;)
- {
- mem_t *row = GetNextRowMYSQL(res);
- if (!row)
- break;
- //printf("|%s|%s|\n",row[0].ptr,row[1].ptr);
- switch(row[0].ptr[0])
- {
- case 'C':
- if (!strcmp(row[0].ptr,"Connections"))
- stat->connections = strtoull(row[1].ptr,0,10);
- break;
- case 'M':
- if (!strcmp(row[0].ptr,"Max_used_connections"))
- stat->max_connections = strtoull(row[1].ptr,0,10);
- break;
- case 'Q':
- if (!strcmp(row[0].ptr,"Queries"))
- stat->queries = strtoull(row[1].ptr,0,10);
- break;
- case 'U':
- if (!strcmp(row[0].ptr,"Uptime"))
- stat->uptime = strtoull(row[1].ptr,0,10);
- break;
- }
- }
- FreeResultMYSQL(res);
- }
- }
- return err;
- }
- ///////////////////////////////////////////////////////////////////////////////
- MySqlServerStats_t * Add3MySqlServerStats
- (
- // return dest
- // calculate: dest = src1 + src2
- MySqlServerStats_t *dest, // NULL or destination (maybe same as source)
- const MySqlServerStats_t *src1, // NULL or first source
- const MySqlServerStats_t *src2 // NULL or second source
- )
- {
- if (dest)
- {
- if (!src1)
- {
- if (src2)
- memcpy(dest,src2,sizeof(*dest));
- else
- InitializeMySqlServerStats(dest);
- }
- else if (!src2)
- {
- DASSERT(src1);
- memcpy(dest,src1,sizeof(*dest));
- }
- else
- {
- DASSERT(src1);
- DASSERT(src2);
- dest->max_connections = src1->max_connections > src2->max_connections
- ? src1->max_connections : src2->max_connections;
- dest->uptime = src1->uptime + src2->uptime;
- dest->connections = src1->connections + src2->connections;
- dest->queries = src1->queries + src2->queries;
- }
- }
- return dest;
- }
- ///////////////////////////////////////////////////////////////////////////////
- MySqlServerStats_t * Sub3MySqlServerStats
- (
- // return dest
- // calculate: dest = src1 - src2
- MySqlServerStats_t *dest, // NULL or destination (maybe same as source)
- const MySqlServerStats_t *src1, // NULL or first source
- const MySqlServerStats_t *src2 // NULL or second source
- )
- {
- if (dest)
- {
- if (!src1)
- {
- if (src2)
- {
- MySqlServerStats_t temp;
- InitializeMySqlServerStats(&temp);
- Sub3MySqlServerStats(dest,&temp,src2);
- }
- else
- InitializeMySqlServerStats(dest);
- }
- else if (!src2)
- {
- DASSERT(src1);
- memcpy(dest,src1,sizeof(*dest));
- }
- else
- {
- DASSERT(src1);
- DASSERT(src2);
- dest->max_connections = src1->max_connections;
- dest->uptime = src1->uptime - src2->uptime;
- dest->connections = src1->connections - src2->connections;
- dest->queries = src1->queries - src2->queries;
- }
- }
- return dest;
- }
- ///////////////////////////////////////////////////////////////////////////////
- MySqlServerStats_t * Max2MySqlServerStats
- (
- // return dest
- // calculate: dest := max(dest,src)
- MySqlServerStats_t *dest, // NULL or destination (maybe same as source)
- const MySqlServerStats_t *src // NULL or source
- )
- {
- if ( src && dest )
- {
- if ( dest->max_connections < src->max_connections )
- dest->max_connections = src->max_connections;
- if ( dest->uptime < src->uptime )
- dest->uptime = src->uptime;
- if ( dest->connections < src->connections )
- dest->connections = src->connections;
- if ( dest->queries < src->queries )
- dest->queries = src->queries;
- }
- return dest;
- }
- //
- ///////////////////////////////////////////////////////////////////////////////
- /////////////// END ///////////////
- ///////////////////////////////////////////////////////////////////////////////
|