55 ClassImp(TMySQLServer);
83 TMySQLServer::TMySQLServer(
const char *db,
const char *uid,
const char *pw)
91 TString errmsg(
"malformed db argument ");
93 SetError(-1, errmsg.Data(),
"TMySQLServer");
98 if (strncmp(url.GetProtocol(),
"mysql", 5)) {
99 SetError(-1,
"protocol in db argument should be mysql://",
"TMySQLServer");
104 const char* dbase = url.GetFile();
106 if (*dbase==
'/') dbase++;
111 ULong_t client_flag = 0;
114 TString optstr = url.GetOptions();
115 TObjArray* optarr = optstr.Tokenize(
"&");
119 while ((obj = next()) != 0) {
120 TString opt = obj->GetName();
122 opt.ReplaceAll(
" ",
"");
123 if (opt.Contains(
"timeout=")) {
125 Int_t timeout = opt.Atoi();
127 UInt_t mysqltimeout = (UInt_t) timeout;
128 mysql_options(fMySQL, MYSQL_OPT_CONNECT_TIMEOUT, (
const char*) &mysqltimeout);
129 if (gDebug) Info(
"TMySQLServer",
"Set timeout %d",timeout);
132 if (opt.Contains(
"read_timeout=")) {
133 #if MYSQL_VERSION_ID >= 40101
135 Int_t timeout = opt.Atoi();
137 UInt_t mysqltimeout = (UInt_t) timeout;
138 mysql_options(fMySQL, MYSQL_OPT_READ_TIMEOUT, (
const char*) &mysqltimeout);
139 if (gDebug) Info(
"TMySQLServer",
"Set read timeout %d", timeout);
142 Warning(
"TMySQLServer",
"MYSQL_OPT_READ_TIMEOUT option not supported by this version of MySql");
146 if (opt.Contains(
"write_timeout=")) {
147 #if MYSQL_VERSION_ID >= 40101
149 Int_t timeout = opt.Atoi();
151 UInt_t mysqltimeout = (UInt_t) timeout;
152 mysql_options(fMySQL, MYSQL_OPT_WRITE_TIMEOUT, (
const char*) &mysqltimeout);
153 if (gDebug) Info(
"TMySQLServer",
"Set write timeout %d", timeout);
156 Warning(
"TMySQLServer",
"MYSQL_OPT_WRITE_TIMEOUT option not supported by this version of MySql");
159 if (opt.Contains(
"reconnect=")) {
160 #if MYSQL_VERSION_ID >= 50013
162 bool reconnect_on = (opt==
"1") || (opt==
"true");
163 mysql_options(fMySQL, MYSQL_OPT_RECONNECT, (
const char*) &reconnect_on);
164 if (gDebug) Info(
"TMySQLServer",
"Set reconnect options %s", (reconnect_on ?
"ON" :
"OFF"));
166 Warning(
"TMySQLServer",
"MYSQL_OPT_RECONNECT option not supported by this version of MySql");
169 if (opt.Contains(
"socket=")) {
170 socket = (obj->GetName()+7);
171 if (gDebug) Info(
"TMySQLServer",
"Use socket %s", socket.Data());
173 if (opt.Contains(
"multi_statements")) {
174 #if MYSQL_VERSION_ID >= 40100
175 client_flag = client_flag | CLIENT_MULTI_STATEMENTS;
176 if (gDebug) Info(
"TMySQLServer",
"Use CLIENT_MULTI_STATEMENTS");
178 Warning(
"TMySQLServer",
"CLIENT_MULTI_STATEMENTS not supported by this version of MySql");
181 if (opt.Contains(
"multi_results")) {
182 #if MYSQL_VERSION_ID >= 40100
183 client_flag = client_flag | CLIENT_MULTI_RESULTS;
184 if (gDebug) Info(
"TMySQLServer",
"Use CLIENT_MULTI_RESULTS");
186 Warning(
"TMySQLServer",
"CLIENT_MULTI_RESULTS not supported by this version of MySql");
189 if (opt.Contains(
"compress")) {
190 mysql_options(fMySQL, MYSQL_OPT_COMPRESS, 0);
191 if (gDebug) Info(
"TMySQLServer",
"Use compressed client/server protocol");
193 if (opt.Contains(
"cnf_file=")) {
194 const char* filename = (obj->GetName()+9);
195 mysql_options(fMySQL, MYSQL_READ_DEFAULT_FILE, filename);
196 if (gDebug) Info(
"TMySQLServer",
"Read mysql options from %s file", filename);
198 if (opt.Contains(
"cnf_group=")) {
199 const char* groupname = (obj->GetName()+10);
200 mysql_options(fMySQL, MYSQL_READ_DEFAULT_GROUP, groupname);
201 if (gDebug) Info(
"TMySQLServer",
"Read mysql options from %s group of my.cnf file", groupname);
209 if (url.GetPort()>0) port = url.GetPort();
211 if (mysql_real_connect(fMySQL, url.GetHost(), uid, pw, dbase, port,
212 (socket.Length()>0) ? socket.Data() : 0 , client_flag)) {
214 fHost = url.GetHost();
218 SetError(mysql_errno(fMySQL), mysql_error(fMySQL),
"TMySQLServer");
226 TMySQLServer::~TMySQLServer()
234 #define CheckConnect(method, res) \
237 if (!IsConnected()) { \
238 SetError(-1,"MySQL server is not connected",method); \
245 #define CheckErrNo(method, force, res) \
247 unsigned int sqlerrno = mysql_errno(fMySQL); \
248 if ((sqlerrno!=0) || force) { \
249 const char* sqlerrmsg = mysql_error(fMySQL); \
250 if (sqlerrno==0) { sqlerrno = 11111; sqlerrmsg = "MySQL error"; } \
251 SetError(sqlerrno, sqlerrmsg, method); \
260 void TMySQLServer::Close(Option_t *)
276 TSQLResult *TMySQLServer::Query(
const char *sql)
278 CheckConnect(
"Query", 0);
280 if (mysql_query(fMySQL, sql))
281 CheckErrNo(
"Query",kTRUE,0);
283 MYSQL_RES *res = mysql_store_result(fMySQL);
284 CheckErrNo(
"Query", kFALSE, 0);
286 return new TMySQLResult(res);
293 Bool_t TMySQLServer::Exec(
const char* sql)
295 CheckConnect(
"Exec", kFALSE);
297 if (mysql_query(fMySQL, sql))
298 CheckErrNo(
"Exec",kTRUE,kFALSE);
306 Int_t TMySQLServer::SelectDataBase(
const char *dbname)
308 CheckConnect(
"SelectDataBase", -1);
310 Int_t res = mysql_select_db(fMySQL, dbname);
311 if (res==0) fDB = dbname;
312 else CheckErrNo(
"SelectDataBase", kTRUE, res);
323 TSQLResult *TMySQLServer::GetDataBases(
const char *wild)
325 CheckConnect(
"GetDataBases", 0);
327 MYSQL_RES *res = mysql_list_dbs(fMySQL, wild);
329 CheckErrNo(
"GetDataBases", kFALSE, 0);
331 return new TMySQLResult(res);
340 TSQLResult *TMySQLServer::GetTables(
const char *dbname,
const char *wild)
342 CheckConnect(
"GetTables", 0);
344 if (SelectDataBase(dbname) != 0)
return 0;
346 MYSQL_RES *res = mysql_list_tables(fMySQL, wild);
348 CheckErrNo(
"GetTables", kFALSE, 0);
350 return new TMySQLResult(res);
357 TList* TMySQLServer::GetTablesList(
const char* wild)
359 CheckConnect(
"GetTablesList", 0);
361 MYSQL_RES *res = mysql_list_tables(fMySQL, wild);
363 CheckErrNo(
"GetTablesList", kFALSE, 0);
365 MYSQL_ROW row = mysql_fetch_row(res);
370 CheckErrNo(
"GetTablesList", kFALSE, lst);
372 const char* tablename = row[0];
377 lst->SetOwner(kTRUE);
379 lst->Add(
new TObjString(tablename));
382 row = mysql_fetch_row(res);
385 mysql_free_result(res);
394 TSQLTableInfo *TMySQLServer::GetTableInfo(
const char* tablename)
396 CheckConnect(
"GetTableInfo", 0);
398 if ((tablename==0) || (*tablename==0))
return 0;
401 sql.Form(
"SELECT * FROM `%s` LIMIT 1", tablename);
403 if (mysql_query(fMySQL, sql.Data()) != 0)
404 CheckErrNo(
"GetTableInfo", kTRUE, 0);
406 MYSQL_RES *res = mysql_store_result(fMySQL);
407 CheckErrNo(
"GetTableInfo", kFALSE, 0);
409 unsigned int numfields = mysql_num_fields(res);
411 MYSQL_FIELD* fields = mysql_fetch_fields(res);
413 sql.Form(
"SHOW COLUMNS FROM `%s`", tablename);
414 TSQLResult* showres = Query(sql.Data());
417 mysql_free_result(res);
423 unsigned int nfield = 0;
427 while ((row = showres->Next()) != 0) {
428 const char* column_name = row->GetField(0);
429 const char* type_name = row->GetField(1);
431 if ((nfield>=numfields) ||
432 (strcmp(column_name, fields[nfield].name)!=0))
434 SetError(-1,
"missmatch in column names",
"GetTableInfo");
438 Int_t sqltype = kSQL_NONE;
440 Int_t data_size = -1;
441 Int_t data_length = -1;
442 Int_t data_scale = -1;
443 Int_t data_sign = -1;
445 if (IS_NUM(fields[nfield].type)) {
446 if (fields[nfield].flags & UNSIGNED_FLAG)
452 Bool_t nullable = (fields[nfield].flags & NOT_NULL_FLAG) == 0;
454 data_length = fields[nfield].length;
455 if (data_length==0) data_length = -1;
457 #if MYSQL_VERSION_ID >= 40100
459 switch (fields[nfield].type) {
460 case MYSQL_TYPE_TINY:
461 case MYSQL_TYPE_SHORT:
462 case MYSQL_TYPE_LONG:
463 case MYSQL_TYPE_INT24:
464 case MYSQL_TYPE_LONGLONG:
465 sqltype = kSQL_INTEGER;
467 case MYSQL_TYPE_DECIMAL:
468 sqltype = kSQL_NUMERIC;
469 data_scale = fields[nfield].decimals;
471 case MYSQL_TYPE_FLOAT:
472 sqltype = kSQL_FLOAT;
474 case MYSQL_TYPE_DOUBLE:
475 sqltype = kSQL_DOUBLE;
477 case MYSQL_TYPE_TIMESTAMP:
478 sqltype = kSQL_TIMESTAMP;
480 case MYSQL_TYPE_DATE:
481 case MYSQL_TYPE_TIME:
482 case MYSQL_TYPE_DATETIME:
483 case MYSQL_TYPE_YEAR:
485 case MYSQL_TYPE_STRING:
486 if (fields[nfield].charsetnr==63)
487 sqltype = kSQL_BINARY;
490 data_size = data_length;
492 case MYSQL_TYPE_VAR_STRING:
493 if (fields[nfield].charsetnr==63)
494 sqltype = kSQL_BINARY;
496 sqltype = kSQL_VARCHAR;
497 data_size = data_length;
499 case MYSQL_TYPE_BLOB:
500 if (fields[nfield].charsetnr==63)
501 sqltype = kSQL_BINARY;
503 sqltype = kSQL_VARCHAR;
504 data_size = data_length;
507 case MYSQL_TYPE_ENUM:
508 case MYSQL_TYPE_GEOMETRY:
509 case MYSQL_TYPE_NULL:
512 if (IS_NUM(fields[nfield].type))
513 sqltype = kSQL_NUMERIC;
520 lst->Add(
new TSQLColumnInfo(column_name,
533 mysql_free_result(res);
536 sql.Form(
"SHOW TABLE STATUS LIKE '%s'", tablename);
538 TSQLTableInfo* info = 0;
540 TSQLResult* stats = Query(sql.Data());
545 while ((row = stats->Next()) != 0) {
546 if (strcmp(row->GetField(0), tablename)!=0) {
550 const char* comments = 0;
551 const char* engine = 0;
552 const char* create_time = 0;
553 const char* update_time = 0;
555 for (
int n=1;n<stats->GetFieldCount();n++) {
556 TString fname = stats->GetFieldName(n);
558 if (fname==
"engine") engine = row->GetField(n);
else
559 if (fname==
"comment") comments = row->GetField(n);
else
560 if (fname==
"create_time") create_time = row->GetField(n);
else
561 if (fname==
"update_time") update_time = row->GetField(n);
564 info =
new TSQLTableInfo(tablename,
578 info =
new TSQLTableInfo(tablename, lst);
589 TSQLResult *TMySQLServer::GetColumns(
const char *dbname,
const char *table,
592 CheckConnect(
"GetColumns", 0);
594 if (SelectDataBase(dbname) != 0)
return 0;
598 sql.Form(
"SHOW COLUMNS FROM %s LIKE '%s'", table, wild);
600 sql.Form(
"SHOW COLUMNS FROM %s", table);
602 return Query(sql.Data());
608 Int_t TMySQLServer::CreateDataBase(
const char *dbname)
610 CheckConnect(
"CreateDataBase", -1);
612 Int_t res = mysql_query(fMySQL, Form(
"CREATE DATABASE %s",dbname));
614 CheckErrNo(
"CreateDataBase", kFALSE, res);
623 Int_t TMySQLServer::DropDataBase(
const char *dbname)
625 CheckConnect(
"DropDataBase", -1);
627 Int_t res = mysql_query(fMySQL, Form(
"DROP DATABASE %s",dbname));
629 CheckErrNo(
"DropDataBase", kFALSE, res);
638 Int_t TMySQLServer::Reload()
640 CheckConnect(
"Reload", -1);
642 Int_t res = mysql_reload(fMySQL);
644 CheckErrNo(
"Reload", kFALSE, res);
653 Int_t TMySQLServer::Shutdown()
655 CheckConnect(
"Shutdown", -1);
659 #if MYSQL_VERSION_ID >= 50001 || \
660 (MYSQL_VERSION_ID < 50000 && MYSQL_VERSION_ID >= 40103)
661 res = mysql_shutdown(fMySQL, SHUTDOWN_DEFAULT);
663 res = mysql_shutdown(fMySQL);
666 CheckErrNo(
"Shutdown", kFALSE, res);
674 const char *TMySQLServer::ServerInfo()
676 CheckConnect(
"ServerInfo", 0);
678 const char* res = mysql_get_server_info(fMySQL);
680 CheckErrNo(
"ServerInfo", kFALSE, res);
692 Bool_t TMySQLServer::HasStatement()
const
694 #if MYSQL_VERSION_ID < 40100
705 TSQLStatement *TMySQLServer::Statement(
const char *sql, Int_t)
707 #if MYSQL_VERSION_ID < 40100
709 SetError(-1,
"Statement class does not supported by MySQL version < 4.1",
"Statement");
713 CheckConnect(
"Statement", 0);
716 SetError(-1,
"no query string specified",
"Statement");
720 MYSQL_STMT *stmt = mysql_stmt_init(fMySQL);
722 CheckErrNo(
"Statement", kTRUE, 0);
724 if (mysql_stmt_prepare(stmt, sql, strlen(sql))) {
725 SetError(mysql_errno(fMySQL), mysql_error(fMySQL),
"Statement");
726 mysql_stmt_close(stmt);
730 return new TMySQLStatement(stmt, fErrorOut);
738 Bool_t TMySQLServer::StartTransaction()
740 CheckConnect(
"StartTransaction", kFALSE);
742 return TSQLServer::StartTransaction();
748 Bool_t TMySQLServer::Commit()
750 CheckConnect(
"Commit", kFALSE);
752 #if MYSQL_VERSION_ID >= 40100
754 if (mysql_commit(fMySQL))
755 CheckErrNo(
"Commit", kTRUE, kFALSE);
761 return TSQLServer::Commit();
770 Bool_t TMySQLServer::Rollback()
772 CheckConnect(
"Rollback", kFALSE);
774 #if MYSQL_VERSION_ID >= 40100
776 if (mysql_rollback(fMySQL))
777 CheckErrNo(
"Rollback", kTRUE, kFALSE);
783 return TSQLServer::Rollback();
795 Bool_t TMySQLServer::PingVerify()
797 CheckConnect(
"Ping", kFALSE);
799 if (mysql_ping(fMySQL)) {
800 if (mysql_ping(fMySQL)) {
801 Error(
"PingVerify",
"not able to automatically reconnect a second time");
802 CheckErrNo(
"Ping", kTRUE, kFALSE);
804 Info(
"PingVerify",
"connection was lost, but could automatically reconnect");
814 Int_t TMySQLServer::Ping()
816 CheckConnect(
"PingInt", kFALSE);
818 return mysql_ping(fMySQL);