TOracleServer.cxx

Go to the documentation of this file.
00001 // @(#)root/oracle:$Id: TOracleServer.cxx 35344 2010-09-16 21:34:21Z pcanal $
00002 // Author: Yan Liu and Shaowen Wang   23/11/04
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2005, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 //////////////////////////////////////////////////////////////////////////
00013 //                                                                      //
00014 // TOracleServer                                                        //
00015 //                                                                      //
00016 // This class implements an OCCI interface to Oracle data bases.        //
00017 // It uses the instantclient10 software available from Oracle.          //
00018 // To install this client software do:                                  //
00019 // 1) Download Instant Client Packages (4 files) from:                  //
00020 //     http://www.oracle.com/technology/software/tech/oci/instantclient/index.html
00021 // 2) Unzip the files into instantclient10_2 (Mac OS X example here):   //
00022 //     unzip instantclient-basic-macosx-10.2.0.4.zip                    //
00023 //     unzip instantclient-sqlplus-macosx-10.2.0.4.zip                  //
00024 //     unzip instantclient-sdk-macosx-10.2.0.4.zip                      //
00025 //     unzip instantclient-jdbc-macosx-10.2.0.4.zip                     //
00026 // 3) Create two symbolic links for the files that have the version     //
00027 //    appended:                                                         //
00028 //      ln -s libclntsh.dylib.10.1 libclntsh.dylib                      //
00029 //      ln -s libocci.dylib.10.1 libocci.dylib                          //
00030 // 4) Add instantclient10_1 directory to your (DY)LD_LIBRARY_PATH       //
00031 //    in your .profile:                                                 //
00032 //      export (DY)LD_LIBRARY_PATH="<pathto>/instantclient10_2"         //
00033 //    Use DY only on Mac OS X.                                          //
00034 // 5) If you also want to use the sqlplus command line app add also     //
00035 //      export SQLPATH="<pathto>/instantclient10_2"                     //
00036 // 6) If you want to connect to a remote db server you will also need   //
00037 //    to create a tnsname.ora file which describes the local_name for   //
00038 //    the remote db servers (at CERN most public machines have this     //
00039 //    file in /etc). If it is not in /etc create TNS_ADMIN:             //
00040 //      export TNS_ADMIN="<path-to-dir-containing-tnsname.ora>"         //
00041 // 7) Test it our with the sqlplus command line app:                    //
00042 //      sqlplus [username][/password]@<local_name>                      //
00043 //    or                                                                //
00044 //      sqlplus [username][/password]@//[hostname][:port][/database]    //
00045 //                                                                      //
00046 //////////////////////////////////////////////////////////////////////////
00047 
00048 
00049 #include "TOracleServer.h"
00050 #include "TOracleResult.h"
00051 #include "TOracleStatement.h"
00052 #include "TSQLColumnInfo.h"
00053 #include "TSQLTableInfo.h"
00054 #include "TUrl.h"
00055 #include "TList.h"
00056 #include "TObjString.h"
00057 
00058 ClassImp(TOracleServer)
00059 
00060 const char* TOracleServer::fgDatimeFormat = "MM/DD/YYYY, HH24:MI:SS";
00061 
00062 
00063 // Reset error and check that server connected
00064 #define CheckConnect(method, res)                       \
00065       ClearError();                                     \
00066       if (!IsConnected()) {                             \
00067          SetError(-1,"Oracle database is not connected",method); \
00068          return res;                                    \
00069       }
00070 
00071 // catch Oracle exception after try block
00072 #define CatchError(method)                           \
00073    catch (SQLException &oraex) {                     \
00074       SetError(oraex.getErrorCode(), oraex.getMessage().c_str(), method); \
00075    }
00076 
00077 //______________________________________________________________________________
00078 TOracleServer::TOracleServer(const char *db, const char *uid, const char *pw)
00079 {
00080    // Open a connection to a Oracle DB server. The db arguments should be
00081    // of the form "oracle://connection_identifier[/<database>]", e.g.:
00082    // "oracle://cmscald.fnal.gov/test". The uid is the username and pw
00083    // the password that should be used for the connection.
00084 
00085    fEnv = 0;
00086    fConn = 0;
00087 
00088    TUrl url(db);
00089 
00090    if (!url.IsValid()) {
00091       TString errmsg = "Malformed db argument ";
00092       errmsg+=db;
00093       SetError(-1, errmsg.Data(), "TOracleServer");
00094       MakeZombie();
00095       return;
00096    }
00097 
00098    if (strncmp(url.GetProtocol(), "oracle", 6)) {
00099       SetError(-1, "protocol in db argument should be oracle://", "TOracleServer");
00100       MakeZombie();
00101       return;
00102    }
00103 
00104    const char *conn_str = url.GetFile();
00105    if (conn_str!=0)
00106      if (*conn_str == '/') conn_str++; //skip leading "/" if appears
00107 
00108    try {
00109       // found out whether to use objet mode
00110       TString options = url.GetOptions();
00111       Int_t pos = options.Index("ObjectMode");
00112       // create environment accordingly
00113       if (pos != kNPOS) {
00114         fEnv = Environment::createEnvironment(Environment::OBJECT);
00115       } else {
00116         fEnv = Environment::createEnvironment();
00117       }
00118       fConn = fEnv->createConnection(uid, pw, conn_str ? conn_str : "");
00119 
00120       fType = "Oracle";
00121       fHost = url.GetHost();
00122       fDB   = conn_str;
00123       fPort = url.GetPort();
00124       fPort = (fPort>0) ? fPort : 1521;
00125       return;
00126 
00127    } CatchError("TOracleServer")
00128 
00129    MakeZombie();
00130 }
00131 
00132 //______________________________________________________________________________
00133 TOracleServer::~TOracleServer()
00134 {
00135    // Close connection to Oracle DB server.
00136 
00137    if (IsConnected())
00138       Close();
00139 }
00140 
00141 
00142 //______________________________________________________________________________
00143 void TOracleServer::Close(Option_t *)
00144 {
00145    // Close connection to Oracle DB server.
00146 
00147    ClearError();
00148 
00149    try {
00150       if (fConn)
00151          fEnv->terminateConnection(fConn);
00152       if (fEnv)
00153          Environment::terminateEnvironment(fEnv);
00154    } CatchError("Close")
00155 
00156    fPort = -1;
00157 }
00158 
00159 //______________________________________________________________________________
00160 TSQLStatement *TOracleServer::Statement(const char *sql, Int_t niter)
00161 {
00162    CheckConnect("Statement",0);
00163 
00164    if (!sql || !*sql) {
00165       SetError(-1, "no query string specified","Statement");
00166       return 0;
00167    }
00168 
00169    try {
00170       oracle::occi::Statement *stmt = fConn->createStatement(sql);
00171 
00172       Blob parblob(fConn);
00173 
00174       return new TOracleStatement(fEnv, fConn, stmt, niter, fErrorOut);
00175 
00176    } CatchError("Statement")
00177 
00178    return 0;
00179 }
00180 
00181 //______________________________________________________________________________
00182 TSQLResult *TOracleServer::Query(const char *sql)
00183 {
00184    // Execute SQL command. Result object must be deleted by the user.
00185    // Returns a pointer to a TSQLResult object if successful, 0 otherwise.
00186 
00187    CheckConnect("Query",0);
00188 
00189    if (!sql || !*sql) {
00190       SetError(-1, "no query string specified","Query");
00191       return 0;
00192    }
00193 
00194    try {
00195       oracle::occi::Statement *stmt = fConn->createStatement();
00196 
00197       // NOTE: before special COUNT query was executed to define number of
00198       // rows in result set. Now it is not requried, while TOracleResult class
00199       // will automatically fetch all rows from resultset when
00200       // GetRowCount() will be called first time.
00201       // It is better do not use GetRowCount() to avoid unnecessary memory usage.
00202 
00203       stmt->setSQL(sql);
00204       stmt->setPrefetchRowCount(1000);
00205       stmt->setPrefetchMemorySize(1000000);
00206       stmt->execute();
00207 
00208       TOracleResult *res = new TOracleResult(fConn, stmt);
00209       return res;
00210    } CatchError("Query")
00211 
00212    return 0;
00213 }
00214 
00215 //______________________________________________________________________________
00216 Bool_t TOracleServer::Exec(const char* sql)
00217 {
00218    // Execute sql command wich does not produce any result set.
00219    // Return kTRUE if succesfull
00220 
00221    CheckConnect("Exec", kFALSE);
00222 
00223    if (!sql || !*sql) {
00224       SetError(-1, "no query string specified","Exec");
00225       return kFALSE;
00226    }
00227 
00228    oracle::occi::Statement *stmt = 0;
00229 
00230    Bool_t res = kFALSE;
00231 
00232    try {
00233       stmt = fConn->createStatement(sql);
00234       stmt->execute();
00235       res = kTRUE;
00236    } CatchError("Exec")
00237 
00238    try {
00239       fConn->terminateStatement(stmt);
00240    } CatchError("Exec")
00241 
00242    return res;
00243 }
00244 
00245 //______________________________________________________________________________
00246 TSQLResult *TOracleServer::GetTables(const char *dbname, const char * /*wild*/)
00247 {
00248    // List all tables in the specified database. Wild is for wildcarding
00249    // "t%" list all tables starting with "t".
00250    // Returns a pointer to a TSQLResult object if successful, 0 otherwise.
00251    // The result object must be deleted by the user.
00252 
00253    // In Oracle 9 and above, table is accessed in schema.table format.
00254    // GetTables returns tables in all schemas accessible for the user.
00255    // Assumption: table ALL_OBJECTS is accessible for the user, which is true in Oracle 10g
00256    // The returned TSQLResult has two columns: schema_name, table_name
00257    // "dbname": if specified, return table list of this schema, or return all tables
00258    // "wild" is not used in this implementation
00259 
00260    CheckConnect("GetTables",0);
00261 
00262    TString sqlstr("SELECT object_name,owner FROM ALL_OBJECTS WHERE object_type='TABLE'");
00263    if (dbname && dbname[0])
00264       sqlstr = sqlstr + " AND owner='" + dbname + "'";
00265 
00266    return Query(sqlstr.Data());
00267 }
00268 
00269 //______________________________________________________________________________
00270 TList* TOracleServer::GetTablesList(const char* wild)
00271 {
00272    CheckConnect("GetTablesList",0);
00273 
00274    TString cmd("SELECT table_name FROM user_tables");
00275    if ((wild!=0) && (*wild!=0))
00276       cmd+=Form(" WHERE table_name LIKE '%s'", wild);
00277 
00278    TSQLStatement* stmt = Statement(cmd);
00279    if (stmt==0) return 0;
00280 
00281    TList* lst = 0;
00282 
00283    if (stmt->Process()) {
00284       stmt->StoreResult();
00285       while (stmt->NextResultRow()) {
00286          const char* tablename = stmt->GetString(0);
00287          if (tablename==0) continue;
00288          if (lst==0) {
00289             lst = new TList;
00290             lst->SetOwner(kTRUE);
00291          }
00292          lst->Add(new TObjString(tablename));
00293       }
00294    }
00295 
00296    delete stmt;
00297 
00298    return lst;
00299 }
00300 
00301 //______________________________________________________________________________
00302 TSQLTableInfo *TOracleServer::GetTableInfo(const char* tablename)
00303 {
00304    // Produces SQL table info
00305    // Object must be deleted by user
00306 
00307    CheckConnect("GetTableInfo",0);
00308 
00309    if ((tablename==0) || (*tablename==0)) return 0;
00310 
00311    TString table(tablename);
00312    table.ToUpper();
00313    TString sql;
00314    sql.Form("SELECT COLUMN_NAME, DATA_TYPE, DATA_LENGTH, DATA_PRECISION, DATA_SCALE, NULLABLE, CHAR_COL_DECL_LENGTH FROM user_tab_columns WHERE table_name = '%s' ORDER BY COLUMN_ID", table.Data());
00315 
00316    TSQLStatement* stmt = Statement(sql.Data(), 10);
00317    if (stmt==0) return 0;
00318 
00319    if (!stmt->Process()) {
00320       delete stmt;
00321       return 0;
00322    }
00323 
00324    TList* lst = 0;
00325 
00326    stmt->StoreResult();
00327 
00328    while (stmt->NextResultRow()) {
00329       const char* columnname = stmt->GetString(0);
00330       TString data_type = stmt->GetString(1);
00331       Int_t data_length = stmt->GetInt(2);      // this is size in bytes
00332       Int_t data_precision = stmt->GetInt(3);
00333       Int_t data_scale = stmt->GetInt(4);
00334       const char* nstr = stmt->GetString(5);
00335       Int_t char_col_decl_length = stmt->GetInt(6);
00336       Int_t data_sign = -1; // no info about sign
00337 
00338       Int_t sqltype = kSQL_NONE;
00339 
00340       if (data_type=="NUMBER") {
00341          sqltype = kSQL_NUMERIC;
00342          if (data_precision<=0) {
00343             data_precision = -1;
00344             data_scale = -1;
00345          } else
00346          if (data_scale<=0)
00347             data_scale = -1;
00348          data_sign = 1;
00349       } else
00350 
00351       if (data_type=="CHAR") {
00352          sqltype = kSQL_CHAR;
00353          data_precision = char_col_decl_length;
00354          data_scale = -1;
00355       } else
00356 
00357       if ((data_type=="VARCHAR") || (data_type=="VARCHAR2")) {
00358          sqltype = kSQL_VARCHAR;
00359          data_precision = char_col_decl_length;
00360          data_scale = -1;
00361       } else
00362 
00363       if (data_type=="FLOAT") {
00364          sqltype = kSQL_FLOAT;
00365          data_scale = -1;
00366          if (data_precision==126) data_precision = -1;
00367          data_sign = 1;
00368       } else
00369 
00370       if (data_type=="BINARY_FLOAT") {
00371          sqltype = kSQL_FLOAT;
00372          data_scale = -1;
00373          data_precision = -1;
00374          data_sign = 1;
00375       } else
00376 
00377       if (data_type=="BINARY_DOUBLE") {
00378          sqltype = kSQL_DOUBLE;
00379          data_scale = -1;
00380          data_precision = -1;
00381          data_sign = 1;
00382       } else
00383 
00384       if (data_type=="LONG") {
00385          sqltype = kSQL_VARCHAR;
00386          data_length = 0x7fffffff; // size of LONG 2^31-1
00387          data_precision = -1;
00388          data_scale = -1;
00389       } else
00390 
00391       if (data_type.Contains("TIMESTAMP")) {
00392          sqltype = kSQL_TIMESTAMP;
00393          data_precision = -1;
00394       }
00395 
00396       Bool_t IsNullable = kFALSE;
00397       if (nstr!=0)
00398          IsNullable = (*nstr=='Y') || (*nstr=='y');
00399 
00400       TSQLColumnInfo* info =
00401          new TSQLColumnInfo(columnname,
00402                             data_type,
00403                             IsNullable,
00404                             sqltype,
00405                             data_length,
00406                             data_precision,
00407                             data_scale,
00408                             data_sign);
00409 
00410       if (lst==0) lst = new TList;
00411       lst->Add(info);
00412    }
00413 
00414    delete stmt;
00415 
00416    return new TSQLTableInfo(tablename, lst);
00417 }
00418 
00419 //______________________________________________________________________________
00420 TSQLResult *TOracleServer::GetColumns(const char * /*dbname*/, const char *tablename,
00421                                       const char * wild)
00422 {
00423    // List all columns in specified table in the specified database.
00424    // Wild is for wildcarding "t%" list all columns starting with "t".
00425    // Returns a pointer to a TSQLResult object if successful, 0 otherwise.
00426    // The result object must be deleted by the user.
00427 
00428    CheckConnect("GetColumns",0);
00429 
00430 //  make no sense, while method is not implemented
00431 //   if (SelectDataBase(dbname) != 0) {
00432 //      SetError(-1, "Database is not connected","GetColumns");
00433 //      return 0;
00434 //   }
00435 
00436    TString sql;
00437    TString table(tablename);
00438    table.ToUpper();
00439    if (wild && wild[0])
00440       sql.Form("select COLUMN_NAME, concat(concat(concat(data_type,'('),data_length),')') \"Type\" FROM user_tab_columns WHERE table_name like '%s' ORDER BY COLUMN_ID", wild);
00441    else
00442       sql.Form("select COLUMN_NAME, concat(concat(concat(data_type,'('),data_length),')') \"Type\" FROM user_tab_columns WHERE table_name = '%s' ORDER BY COLUMN_ID", table.Data()); 
00443    return Query(sql);
00444 }
00445 
00446 //______________________________________________________________________________
00447 Int_t TOracleServer::SelectDataBase(const char * /*dbname*/)
00448 {
00449    // Select a database. Returns 0 if successful, non-zero otherwise.
00450    // NOT IMPLEMENTED.
00451 
00452    CheckConnect("SelectDataBase", -1);
00453 
00454    // do nothing and return success code
00455    return 0;
00456 }
00457 
00458 //______________________________________________________________________________
00459 TSQLResult *TOracleServer::GetDataBases(const char * /*wild*/)
00460 {
00461    // List all available databases. Wild is for wildcarding "t%" list all
00462    // databases starting with "t".
00463    // Returns a pointer to a TSQLResult object if successful, 0 otherwise.
00464    // The result object must be deleted by the user.
00465    // NOT IMPLEMENTED.
00466 
00467    CheckConnect("GetDataBases",0);
00468 
00469    return 0;
00470 }
00471 
00472 //______________________________________________________________________________
00473 Int_t TOracleServer::CreateDataBase(const char * /*dbname*/)
00474 {
00475    // Create a database. Returns 0 if successful, non-zero otherwise.
00476    // NOT IMPLEMENTED.
00477 
00478    CheckConnect("CreateDataBase",-1);
00479 
00480    return -1;
00481 }
00482 
00483 //______________________________________________________________________________
00484 Int_t TOracleServer::DropDataBase(const char * /*dbname*/)
00485 {
00486    // Drop (i.e. delete) a database. Returns 0 if successful, non-zero
00487    // otherwise.
00488    // NOT IMPLEMENTED.
00489 
00490    CheckConnect("DropDataBase",-1);
00491 
00492    return -1;
00493 }
00494 
00495 //______________________________________________________________________________
00496 Int_t TOracleServer::Reload()
00497 {
00498    // Reload permission tables. Returns 0 if successful, non-zero
00499    // otherwise. User must have reload permissions.
00500    // NOT IMPLEMENTED.
00501 
00502    CheckConnect("Reload", -1);
00503 
00504    return -1;
00505 }
00506 
00507 //______________________________________________________________________________
00508 Int_t TOracleServer::Shutdown()
00509 {
00510    // Shutdown the database server. Returns 0 if successful, non-zero
00511    // otherwise. User must have shutdown permissions.
00512    // NOT IMPLEMENTED.
00513 
00514    CheckConnect("Shutdown", -1);
00515 
00516    return -1;
00517 }
00518 
00519 //______________________________________________________________________________
00520 const char *TOracleServer::ServerInfo()
00521 {
00522    // Return Oracle server version info.
00523 
00524    CheckConnect("ServerInfo", 0);
00525 
00526    fInfo = "Oracle";
00527    TSQLStatement* stmt = Statement("select * from v$version");
00528    if (stmt!=0) {
00529        stmt->EnableErrorOutput(kFALSE);
00530        if (stmt->Process()) {
00531           fInfo = "";
00532           stmt->StoreResult();
00533           while (stmt->NextResultRow()) {
00534              if (fInfo.Length()>0) fInfo += "\n";
00535              fInfo += stmt->GetString(0);
00536           }
00537        }
00538        delete stmt;
00539    }
00540 
00541    return fInfo.Data();
00542 }
00543 
00544 //______________________________________________________________________________
00545 Bool_t TOracleServer::StartTransaction()
00546 {
00547    // Call Commit() to submit all chanes, done before.
00548    // Commit() ot Rollback() must be used to complete submitted actions or cancel them
00549 
00550    return Commit();
00551 }
00552 
00553 //______________________________________________________________________________
00554 Bool_t TOracleServer::Commit()
00555 {
00556    // Commits all changes made since the previous Commit() or Rollback()
00557    // Return kTRUE if OK
00558 
00559    CheckConnect("Commit", kFALSE);
00560 
00561    try {
00562       fConn->commit();
00563       return kTRUE;
00564    } CatchError("Commit")
00565 
00566    return kFALSE;
00567 }
00568 
00569 //______________________________________________________________________________
00570 Bool_t TOracleServer::Rollback()
00571 {
00572    // Drops all changes made since the previous Commit() or Rollback()
00573    // Return kTRUE if OK
00574 
00575    CheckConnect("Rollback", kFALSE);
00576 
00577    try {
00578       fConn->rollback();
00579       return kTRUE;
00580    } CatchError("Rollback")
00581 
00582    return kFALSE;
00583 }
00584 
00585 //______________________________________________________________________________
00586 void TOracleServer::SetDatimeFormat(const char* fmt)
00587 {
00588    // set format for converting timestamps or date field into string
00589    // default value is "MM/DD/YYYY, HH24:MI:SS"
00590 
00591    if (fmt==0) fmt = "MM/DD/YYYY, HH24:MI:SS";
00592    fgDatimeFormat = fmt;
00593 }
00594 
00595 //______________________________________________________________________________
00596 const char* TOracleServer::GetDatimeFormat()
00597 {
00598    // return value of actul convertion format from timestamps or date to string
00599 
00600    return fgDatimeFormat;
00601 }

Generated on Tue Jul 5 15:14:39 2011 for ROOT_528-00b_version by  doxygen 1.5.1