29 ClassImp(TODBCServer);
81 TODBCServer::TODBCServer(
const char *db,
const char *uid,
const char *pw) :
85 Bool_t simpleconnect = kTRUE;
92 if ((strncmp(db,
"odbc", 4)!=0) || (strlen(db)<8)) {
93 SetError(-1,
"db argument should be started from odbc...",
"TODBCServer");
97 if (strncmp(db,
"odbc://", 7)==0) {
100 SetError(-1, Form(
"not valid URL: %s", db),
"TODBCServer");
103 const char* driver =
"MyODBC";
104 const char* dbase = url.GetFile();
106 if (*dbase==
'/') dbase++;
108 if (((uid==0) || (*uid==0)) && (strlen(url.GetUser())>0)) {
110 pw = url.GetPasswd();
113 if (strlen(url.GetOptions())!=0) driver = url.GetOptions();
115 connstr.Form(
"DRIVER={%s};"
121 driver, url.GetHost(), dbase, uid, pw);
123 connstr += Form(
"PORT=%d;", url.GetPort());
125 fHost = url.GetHost();
126 fPort = url.GetPort()>0 ? url.GetPort() : 1;
128 simpleconnect = kFALSE;
130 if (strncmp(db,
"odbcd://", 8)==0) {
132 simpleconnect = kFALSE;
134 if (strncmp(db,
"odbcn://", 8)==0) {
136 simpleconnect = kTRUE;
138 SetError(-1,
"db argument is invalid",
"TODBCServer");
142 retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &fHenv);
143 if (ExtractErrors(retcode,
"TODBCServer"))
goto zombie;
146 retcode = SQLSetEnvAttr(fHenv, SQL_ATTR_ODBC_VERSION, (
void*)SQL_OV_ODBC3, 0);
147 if (ExtractErrors(retcode,
"TODBCServer"))
goto zombie;
150 retcode = SQLAllocHandle(SQL_HANDLE_DBC, fHenv, &fHdbc);
151 if (ExtractErrors(retcode,
"TODBCServer"))
goto zombie;
154 retcode = SQLSetConnectAttr(fHdbc, SQL_LOGIN_TIMEOUT, (SQLPOINTER) 5, 0);
155 if (ExtractErrors(retcode,
"TODBCServer"))
goto zombie;
165 retcode = SQLConnect(fHdbc, (SQLCHAR*) connstr.Data(), SQL_NTS,
166 (SQLCHAR*) uid, SQL_NTS,
167 (SQLCHAR*) pw, SQL_NTS);
169 retcode = SQLDriverConnect(fHdbc, hwnd,
170 (SQLCHAR*) connstr.Data(), SQL_NTS,
171 (SQLCHAR*) sbuf, sizeof(sbuf), &reslen, SQL_DRIVER_NOPROMPT);
173 if (ExtractErrors(retcode, "TODBCServer")) goto zombie;
177 retcode = SQLGetInfo(fHdbc, SQL_USER_NAME, sbuf, sizeof(sbuf), &reslen);
178 if (ExtractErrors(retcode, "TODBCServer")) goto zombie;
181 retcode = SQLGetInfo(fHdbc, SQL_DBMS_NAME, sbuf, sizeof(sbuf), &reslen);
182 if (ExtractErrors(retcode, "TODBCServer")) goto zombie;
186 retcode = SQLGetInfo(fHdbc, SQL_DBMS_VER, sbuf, sizeof(sbuf), &reslen);
187 if (ExtractErrors(retcode, "TODBCServer")) goto zombie;
192 retcode = SQLGetConnectAttr(fHdbc, SQL_ATTR_CURRENT_CATALOG, sbuf, sizeof(sbuf), &reslen1);
193 if (ExtractErrors(retcode, "TODBCServer")) goto zombie;
194 if (fDB.Length()==0) fDB = sbuf;
196 retcode = SQLGetInfo(fHdbc, SQL_SERVER_NAME, sbuf, sizeof(sbuf), &reslen);
197 if (ExtractErrors(retcode, "TODBCServer")) goto zombie;
198 if (fHost.Length()==0) fHost = sbuf;
227 TODBCServer::~TODBCServer()
237 TList* TODBCServer::ListData(Bool_t isdrivers)
242 retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);
243 if ((retcode!=SQL_SUCCESS) && (retcode!=SQL_SUCCESS_WITH_INFO))
return 0;
245 retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (
void*)SQL_OV_ODBC3, 0);
246 if ((retcode!=SQL_SUCCESS) && (retcode!=SQL_SUCCESS_WITH_INFO))
return 0;
250 char namebuf[2048], optbuf[2048];
251 SQLSMALLINT reslen1, reslen2;
254 strlcpy(namebuf,
"",2048);
255 strlcpy(optbuf,
"",2048);
257 retcode = SQLDrivers(henv, (lst==0 ? SQL_FETCH_FIRST : SQL_FETCH_NEXT),
258 (SQLCHAR*) namebuf,
sizeof(namebuf), &reslen1,
259 (SQLCHAR*) optbuf,
sizeof(optbuf), &reslen2);
261 retcode = SQLDataSources(henv, (lst==0 ? SQL_FETCH_FIRST : SQL_FETCH_NEXT),
262 (SQLCHAR*) namebuf,
sizeof(namebuf), &reslen1,
263 (SQLCHAR*) optbuf,
sizeof(optbuf), &reslen2);
265 if (retcode==SQL_NO_DATA)
break;
266 if ((retcode==SQL_SUCCESS) || (retcode==SQL_SUCCESS_WITH_INFO)) {
269 lst->SetOwner(kTRUE);
271 for (
int n=0;n<reslen2-1;n++)
272 if (optbuf[n]==
'\0') optbuf[n] =
';';
274 lst->Add(
new TNamed(namebuf, optbuf));
276 }
while ((retcode==SQL_SUCCESS) || (retcode==SQL_SUCCESS_WITH_INFO));
278 SQLFreeHandle(SQL_HANDLE_ENV, henv);
291 TList* TODBCServer::GetDrivers()
293 return ListData(kTRUE);
300 void TODBCServer::PrintDrivers()
302 TList* lst = GetDrivers();
303 std::cout <<
"List of ODBC drivers:" << std::endl;
306 while ((n = (TNamed*) iter()) != 0)
307 std::cout <<
" " << n->GetName() <<
" : " << n->GetTitle() << std::endl;
317 TList* TODBCServer::GetDataSources()
319 return ListData(kFALSE);
326 void TODBCServer::PrintDataSources()
328 TList* lst = GetDataSources();
329 std::cout <<
"List of ODBC data sources:" << std::endl;
332 while ((n = (TNamed*) iter()) != 0)
333 std::cout <<
" " << n->GetName() <<
" : " << n->GetTitle() << std::endl;
340 Bool_t TODBCServer::ExtractErrors(SQLRETURN retcode,
const char* method)
342 if ((retcode==SQL_SUCCESS) || (retcode==SQL_SUCCESS_WITH_INFO))
return kFALSE;
350 while (SQLGetDiagRec(SQL_HANDLE_ENV, fHenv, ++i, state, &native, text,
351 sizeof(text), &len ) == SQL_SUCCESS)
353 SetError(native, (
const char*) text, method);
357 while (SQLGetDiagRec(SQL_HANDLE_DBC, fHdbc, ++i, state, &native, text,
358 sizeof(text), &len ) == SQL_SUCCESS)
360 SetError(native, (
const char*) text, method);
366 #define CheckConnect(method, res) \
369 if (!IsConnected()) { \
370 SetError(-1,"ODBC driver is not connected",method); \
378 void TODBCServer::Close(Option_t *)
380 SQLDisconnect(fHdbc);
381 SQLFreeHandle(SQL_HANDLE_DBC, fHdbc);
382 SQLFreeHandle(SQL_HANDLE_ENV, fHenv);
391 TSQLResult *TODBCServer::Query(
const char *sql)
393 CheckConnect(
"Query", 0);
398 SQLAllocHandle(SQL_HANDLE_STMT, fHdbc, &hstmt);
400 retcode = SQLExecDirect(hstmt, (SQLCHAR*) sql, SQL_NTS);
401 if (ExtractErrors(retcode,
"Query")) {
402 SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
406 return new TODBCResult(hstmt);
413 Bool_t TODBCServer::Exec(
const char* sql)
415 CheckConnect(
"Exec", 0);
420 SQLAllocHandle(SQL_HANDLE_STMT, fHdbc, &hstmt);
422 retcode = SQLExecDirect(hstmt, (SQLCHAR*) sql, SQL_NTS);
424 Bool_t res = !ExtractErrors(retcode,
"Exec");
426 SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
436 Int_t TODBCServer::SelectDataBase(
const char *db)
438 CheckConnect(
"SelectDataBase", -1);
440 SQLRETURN retcode = SQLSetConnectAttr(fHdbc, SQL_ATTR_CURRENT_CATALOG, (SQLCHAR*) db, SQL_NTS);
441 if (ExtractErrors(retcode,
"SelectDataBase"))
return -1;
454 TSQLResult *TODBCServer::GetDataBases(
const char *)
456 CheckConnect(
"GetDataBases", 0);
467 TSQLResult *TODBCServer::GetTables(
const char*,
const char* wild)
469 CheckConnect(
"GetTables", 0);
474 SQLAllocHandle(SQL_HANDLE_STMT, fHdbc, &hstmt);
476 SQLCHAR* schemaName = 0;
477 SQLSMALLINT schemaNameLength = 0;
491 SQLCHAR* tableName = 0;
492 SQLSMALLINT tableNameLength = 0;
494 if ((wild!=0) && (strlen(wild)!=0)) {
495 tableName = (SQLCHAR*) wild;
496 tableNameLength = strlen(wild);
497 SQLSetStmtAttr(hstmt, SQL_ATTR_METADATA_ID, (SQLPOINTER) SQL_FALSE, 0);
500 retcode = SQLTables(hstmt, NULL, 0, schemaName, schemaNameLength, tableName, tableNameLength, (SQLCHAR*)
"TABLE", 5);
501 if (ExtractErrors(retcode,
"GetTables")) {
502 SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
506 return new TODBCResult(hstmt);
513 TList* TODBCServer::GetTablesList(
const char* wild)
515 CheckConnect(
"GetTablesList", 0);
517 TSQLResult* res = GetTables(0, wild);
518 if (res==0)
return 0;
524 while ((row = res->Next())!=0) {
525 const char* tablename = row->GetField(2);
530 lst->SetOwner(kTRUE);
532 lst->Add(
new TObjString(tablename));
547 TSQLTableInfo* TODBCServer::GetTableInfo(
const char* tablename)
549 CheckConnect(
"GetTableInfo", 0);
551 #define STR_LEN 128+1
552 #define REM_LEN 254+1
556 SQLCHAR szCatalog[STR_LEN], szSchema[STR_LEN];
557 SQLCHAR szTableName[STR_LEN], szColumnName[STR_LEN];
558 SQLCHAR szTypeName[STR_LEN], szRemarks[REM_LEN];
559 SQLCHAR szColumnDefault[STR_LEN], szIsNullable[STR_LEN];
560 SQLLEN columnSize, bufferLength, charOctetLength, ordinalPosition;
561 SQLSMALLINT dataType, decimalDigits, numPrecRadix, nullable;
562 SQLSMALLINT sqlDataType, datetimeSubtypeCode;
568 SQLLEN cbCatalog, cbSchema, cbTableName, cbColumnName;
569 SQLLEN cbDataType, cbTypeName, cbColumnSize, cbBufferLength;
570 SQLLEN cbDecimalDigits, cbNumPrecRadix, cbNullable, cbRemarks;
571 SQLLEN cbColumnDefault, cbSQLDataType, cbDatetimeSubtypeCode, cbCharOctetLength;
572 SQLLEN cbOrdinalPosition, cbIsNullable;
575 SQLAllocHandle(SQL_HANDLE_STMT, fHdbc, &hstmt);
577 retcode = SQLColumns(hstmt, NULL, 0, NULL, 0, (SQLCHAR*) tablename, SQL_NTS, NULL, 0);
578 if (ExtractErrors(retcode,
"GetTableInfo")) {
579 SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
587 SQLBindCol(hstmt, 1, SQL_C_CHAR, szCatalog, STR_LEN,&cbCatalog);
588 SQLBindCol(hstmt, 2, SQL_C_CHAR, szSchema, STR_LEN, &cbSchema);
589 SQLBindCol(hstmt, 3, SQL_C_CHAR, szTableName, STR_LEN,&cbTableName);
590 SQLBindCol(hstmt, 4, SQL_C_CHAR, szColumnName, STR_LEN, &cbColumnName);
591 SQLBindCol(hstmt, 5, SQL_C_SSHORT, &dataType, 0, &cbDataType);
592 SQLBindCol(hstmt, 6, SQL_C_CHAR, szTypeName, STR_LEN, &cbTypeName);
593 SQLBindCol(hstmt, 7, SQL_C_SLONG, &columnSize, 0, &cbColumnSize);
594 SQLBindCol(hstmt, 8, SQL_C_SLONG, &bufferLength, 0, &cbBufferLength);
595 SQLBindCol(hstmt, 9, SQL_C_SSHORT, &decimalDigits, 0, &cbDecimalDigits);
596 SQLBindCol(hstmt, 10, SQL_C_SSHORT, &numPrecRadix, 0, &cbNumPrecRadix);
597 SQLBindCol(hstmt, 11, SQL_C_SSHORT, &nullable, 0, &cbNullable);
598 SQLBindCol(hstmt, 12, SQL_C_CHAR, szRemarks, REM_LEN, &cbRemarks);
599 SQLBindCol(hstmt, 13, SQL_C_CHAR, szColumnDefault, STR_LEN, &cbColumnDefault);
600 SQLBindCol(hstmt, 14, SQL_C_SSHORT, &sqlDataType, 0, &cbSQLDataType);
601 SQLBindCol(hstmt, 15, SQL_C_SSHORT, &datetimeSubtypeCode, 0, &cbDatetimeSubtypeCode);
602 SQLBindCol(hstmt, 16, SQL_C_SLONG, &charOctetLength, 0, &cbCharOctetLength);
603 SQLBindCol(hstmt, 17, SQL_C_SLONG, &ordinalPosition, 0, &cbOrdinalPosition);
604 SQLBindCol(hstmt, 18, SQL_C_CHAR, szIsNullable, STR_LEN, &cbIsNullable);
606 retcode = SQLFetch(hstmt);
608 while ((retcode==SQL_SUCCESS) || (retcode==SQL_SUCCESS_WITH_INFO)) {
610 Int_t sqltype = kSQL_NONE;
612 Int_t data_size = -1;
613 Int_t data_length = -1;
614 Int_t data_scale = -1;
615 Int_t data_sign = -1;
620 data_size = columnSize;
621 data_length = charOctetLength;
624 case SQL_LONGVARCHAR:
625 sqltype = kSQL_VARCHAR;
626 data_size = columnSize;
627 data_length = charOctetLength;
631 sqltype = kSQL_NUMERIC;
632 data_size = columnSize;
633 data_length = columnSize;
634 data_scale = decimalDigits;
639 sqltype = kSQL_INTEGER;
640 data_size = columnSize;
644 sqltype = kSQL_FLOAT;
645 data_size = columnSize;
649 sqltype = kSQL_DOUBLE;
650 data_size = columnSize;
655 case SQL_LONGVARBINARY:
656 sqltype = kSQL_BINARY;
657 data_size = columnSize;
659 case SQL_TYPE_TIMESTAMP:
660 sqltype = kSQL_TIMESTAMP;
661 data_size = columnSize;
665 if (lst==0) lst =
new TList;
667 lst->Add(
new TSQLColumnInfo((
const char*) szColumnName,
668 (
const char*) szTypeName,
676 retcode = SQLFetch(hstmt);
679 SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
681 return new TSQLTableInfo(tablename, lst);
690 TSQLResult *TODBCServer::GetColumns(
const char*,
const char *table,
const char*)
692 CheckConnect(
"GetColumns", 0);
697 SQLAllocHandle(SQL_HANDLE_STMT, fHdbc, &hstmt);
699 retcode = SQLColumns(hstmt, NULL, 0, NULL, 0, (SQLCHAR*) table, SQL_NTS, NULL, 0);
700 if (ExtractErrors(retcode,
"GetColumns")) {
701 SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
705 return new TODBCResult(hstmt);
711 Int_t TODBCServer::GetMaxIdentifierLength()
713 CheckConnect(
"GetMaxIdentifierLength", 20);
715 SQLUINTEGER info = 0;
718 retcode = SQLGetInfo(fHdbc, SQL_MAX_IDENTIFIER_LEN, (SQLPOINTER)&info,
sizeof(info), NULL);
720 if (ExtractErrors(retcode,
"GetMaxIdentifierLength"))
return 20;
728 Int_t TODBCServer::CreateDataBase(
const char*)
730 CheckConnect(
"CreateDataBase", -1);
739 Int_t TODBCServer::DropDataBase(
const char*)
741 CheckConnect(
"DropDataBase", -1);
750 Int_t TODBCServer::Reload()
752 CheckConnect(
"Reload", -1);
761 Int_t TODBCServer::Shutdown()
763 CheckConnect(
"Shutdown", -1);
771 const char *TODBCServer::ServerInfo()
773 CheckConnect(
"ServerInfo", 0);
782 TSQLStatement *TODBCServer::Statement(
const char *sql, Int_t bufsize)
784 CheckConnect(
"Statement", 0);
787 SetError(-1,
"no query string specified",
"Statement");
801 retcode = SQLAllocHandle(SQL_HANDLE_STMT, fHdbc, &hstmt);
802 if (ExtractErrors(retcode,
"Statement"))
return 0;
804 retcode = SQLPrepare(hstmt, (SQLCHAR*) sql, SQL_NTS);
805 if (ExtractErrors(retcode,
"Statement")) {
806 SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
810 return new TODBCStatement(hstmt, bufsize, fErrorOut);
818 Bool_t TODBCServer::StartTransaction()
820 CheckConnect(
"StartTransaction", kFALSE);
822 SQLUINTEGER info = 0;
825 retcode = SQLGetInfo(fHdbc, SQL_TXN_CAPABLE, (SQLPOINTER)&info,
sizeof(info), NULL);
826 if (ExtractErrors(retcode,
"StartTransaction"))
return kFALSE;
829 SetError(-1,
"Transactions not supported",
"StartTransaction");
833 if (!Commit())
return kFALSE;
835 retcode = SQLSetConnectAttr(fHdbc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER) SQL_AUTOCOMMIT_OFF, 0);
836 if (ExtractErrors(retcode,
"StartTransaction"))
return kFALSE;
845 Bool_t TODBCServer::EndTransaction(Bool_t commit)
847 const char* method = commit ?
"Commit" :
"Rollback";
849 CheckConnect(method, kFALSE);
851 SQLRETURN retcode = SQLEndTran(SQL_HANDLE_DBC, fHdbc, commit ? SQL_COMMIT : SQL_ROLLBACK);
852 if (ExtractErrors(retcode, method))
return kFALSE;
854 retcode = SQLSetConnectAttr(fHdbc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER) SQL_AUTOCOMMIT_ON, 0);
862 Bool_t TODBCServer::Commit()
864 return EndTransaction(kTRUE);
870 Bool_t TODBCServer::Rollback()
872 return EndTransaction(kFALSE);