Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
TOracleServer.cxx
Go to the documentation of this file.
1// @(#)root/oracle:$Id$
2// Author: Yan Liu and Shaowen Wang 23/11/04
3
4/*************************************************************************
5 * Copyright (C) 1995-2005, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11
12//////////////////////////////////////////////////////////////////////////
13// //
14// TOracleServer //
15// //
16// This class implements an OCCI interface to Oracle data bases. //
17// It uses the instantclient10 software available from Oracle. //
18// To install this client software do: //
19// 1) Download Instant Client Packages (4 files) from: //
20// http://www.oracle.com/technology/software/tech/oci/instantclient/index.html
21// 2) Unzip the files into instantclient10_2 (Mac OS X example here): //
22// unzip instantclient-basic-macosx-10.2.0.4.zip //
23// unzip instantclient-sqlplus-macosx-10.2.0.4.zip //
24// unzip instantclient-sdk-macosx-10.2.0.4.zip //
25// unzip instantclient-jdbc-macosx-10.2.0.4.zip //
26// 3) Create two symbolic links for the files that have the version //
27// appended: //
28// ln -s libclntsh.dylib.10.1 libclntsh.dylib //
29// ln -s libocci.dylib.10.1 libocci.dylib //
30// 4) Add instantclient10_1 directory to your (DY)LD_LIBRARY_PATH //
31// in your .profile: //
32// export (DY)LD_LIBRARY_PATH="<pathto>/instantclient10_2" //
33// Use DY only on Mac OS X. //
34// 5) If you also want to use the sqlplus command line app add also //
35// export SQLPATH="<pathto>/instantclient10_2" //
36// 6) If you want to connect to a remote db server you will also need //
37// to create a tnsname.ora file which describes the local_name for //
38// the remote db servers (at CERN most public machines have this //
39// file in /etc). If it is not in /etc create TNS_ADMIN: //
40// export TNS_ADMIN="<path-to-dir-containing-tnsname.ora>" //
41// 7) Test it our with the sqlplus command line app: //
42// sqlplus [username][/password]@<local_name> //
43// or //
44// sqlplus [username][/password]@//[hostname][:port][/database] //
45// //
46//////////////////////////////////////////////////////////////////////////
47
48
49#include "TOracleServer.h"
50#include "TOracleResult.h"
51#include "TOracleStatement.h"
52#include "TSQLColumnInfo.h"
53#include "TSQLTableInfo.h"
54#include "TUrl.h"
55#include "TList.h"
56#include "TObjString.h"
57
58#ifndef R__WIN32
59#include <sys/time.h>
60#endif
61
62#include <occi.h>
63
65
66const char *TOracleServer::fgDatimeFormat = "MM/DD/YYYY, HH24:MI:SS";
67
68
69// Reset error and check that server connected
70#define CheckConnect(method, res) \
71 ClearError(); \
72 if (!IsConnected()) { \
73 SetError(-1,"Oracle database is not connected",method); \
74 return res; \
75 }
76
77// catch Oracle exception after try block
78#define CatchError(method) \
79 catch (oracle::occi::SQLException &oraex) { \
80 SetError(oraex.getErrorCode(), oraex.getMessage().c_str(), method); \
81 }
82
83////////////////////////////////////////////////////////////////////////////////
84/// Open a connection to a Oracle DB server. The db arguments should be
85/// of the form "oracle://connection_identifier[/<database>]", e.g.:
86/// "oracle://cmscald.fnal.gov/test". The uid is the username and pw
87/// the password that should be used for the connection.
88
89TOracleServer::TOracleServer(const char *db, const char *uid, const char *pw)
90{
91 if (gDebug>0) {
92 // this code is necessary to guarantee, that libclntsh.so will be
93 // linked to libOracle.so.
94 sword major_version(0), minor_version(0), update_num(0), patch_num(0), port_update_num(0);
95 OCIClientVersion(&major_version, &minor_version, &update_num, &patch_num, &port_update_num);
96 Info("TOracleServer","Oracle Call Interface version %u.%u.%u.%u.%u",
97 (unsigned) major_version, (unsigned) minor_version, (unsigned) update_num, (unsigned) patch_num, (unsigned) port_update_num);
98 }
99
100 TUrl url(db);
101
102 if (!url.IsValid()) {
103 TString errmsg = "Malformed db argument ";
104 errmsg+=db;
105 SetError(-1, errmsg.Data(), "TOracleServer");
106 MakeZombie();
107 return;
108 }
109
110 if (strncmp(url.GetProtocol(), "oracle", 6)) {
111 SetError(-1, "protocol in db argument should be oracle://", "TOracleServer");
112 MakeZombie();
113 return;
114 }
115
116 const char *conn_str = url.GetFile();
117 if (conn_str)
118 if (*conn_str == '/') conn_str++; //skip leading "/" if appears
119
120 try {
121 // found out whether to use objet mode
122 TString options = url.GetOptions();
123 Int_t pos = options.Index("ObjectMode");
124 // create environment accordingly
125 if (pos != kNPOS) {
126 fEnv = oracle::occi::Environment::createEnvironment(oracle::occi::Environment::OBJECT);
127 } else {
128 fEnv = oracle::occi::Environment::createEnvironment();
129 }
130 fConn = fEnv->createConnection(uid, pw, conn_str ? conn_str : "");
131
132 fType = "Oracle";
133 fHost = url.GetHost();
134 fDB = conn_str;
135 fPort = url.GetPort();
136 fPort = (fPort>0) ? fPort : 1521;
137 return;
138
139 } CatchError("TOracleServer")
140
141 MakeZombie();
142}
143
144////////////////////////////////////////////////////////////////////////////////
145/// Close connection to Oracle DB server.
146
148{
149 if (IsConnected())
150 Close();
151}
152
153////////////////////////////////////////////////////////////////////////////////
154/// Close connection to Oracle DB server.
155
157{
158 ClearError();
159
160 try {
161 if (fConn)
162 fEnv->terminateConnection(fConn);
163 if (fEnv)
164 oracle::occi::Environment::terminateEnvironment(fEnv);
165 } CatchError("Close")
166
167 fPort = -1;
168}
169
170////////////////////////////////////////////////////////////////////////////////
171
173{
174 CheckConnect("Statement", nullptr);
175
176 if (!sql || !*sql) {
177 SetError(-1, "no query string specified","Statement");
178 return nullptr;
179 }
180
181 try {
182 oracle::occi::Statement *stmt = fConn->createStatement(sql);
183
184 oracle::occi::Blob parblob(fConn);
185
186 return new TOracleStatement(fEnv, fConn, stmt, niter, fErrorOut);
187
188 } CatchError("Statement")
189
190 return nullptr;
191}
192
193////////////////////////////////////////////////////////////////////////////////
194/// Execute SQL command. Result object must be deleted by the user.
195/// Returns a pointer to a TSQLResult object if successful, 0 otherwise.
196
198{
199 CheckConnect("Query", nullptr);
200
201 if (!sql || !*sql) {
202 SetError(-1, "no query string specified","Query");
203 return nullptr;
204 }
205
206 try {
207 oracle::occi::Statement *stmt = fConn->createStatement();
208
209 // NOTE: before special COUNT query was executed to define number of
210 // rows in result set. Now it is not required, while TOracleResult class
211 // will automatically fetch all rows from result set when
212 // GetRowCount() will be called first time.
213 // It is better do not use GetRowCount() to avoid unnecessary memory usage.
214
215 stmt->setSQL(sql);
216 stmt->setPrefetchRowCount(1000);
217 stmt->setPrefetchMemorySize(1000000);
218 stmt->execute();
219
220 TOracleResult *res = new TOracleResult(fConn, stmt);
221 return res;
222 } CatchError("Query")
223
224 return nullptr;
225}
226
227////////////////////////////////////////////////////////////////////////////////
228/// Execute sql command which does not produce any result set.
229/// Return kTRUE if successful
230
232{
233 CheckConnect("Exec", kFALSE);
234
235 if (!sql || !*sql) {
236 SetError(-1, "no query string specified","Exec");
237 return kFALSE;
238 }
239
240 oracle::occi::Statement *stmt = nullptr;
241
242 Bool_t res = kFALSE;
243
244 try {
245 stmt = fConn->createStatement(sql);
246 stmt->execute();
247 res = kTRUE;
248 } CatchError("Exec")
249
250 try {
251 fConn->terminateStatement(stmt);
252 } CatchError("Exec")
253
254 return res;
255}
256
257////////////////////////////////////////////////////////////////////////////////
258/// List all tables in the specified database. Wild is for wildcarding
259/// "t%" list all tables starting with "t".
260/// Returns a pointer to a TSQLResult object if successful, 0 otherwise.
261/// The result object must be deleted by the user.
262
263TSQLResult *TOracleServer::GetTables(const char *dbname, const char * /*wild*/)
264{
265 // In Oracle 9 and above, table is accessed in schema.table format.
266 // GetTables returns tables in all schemas accessible for the user.
267 // Assumption: table ALL_OBJECTS is accessible for the user, which is true in Oracle 10g
268 // The returned TSQLResult has two columns: schema_name, table_name
269 // "dbname": if specified, return table list of this schema, or return all tables
270 // "wild" is not used in this implementation
271
272 CheckConnect("GetTables", nullptr);
273
274 TString sqlstr("SELECT object_name,owner FROM ALL_OBJECTS WHERE object_type='TABLE'");
275 if (dbname && dbname[0])
276 sqlstr = sqlstr + " AND owner='" + dbname + "'";
277
278 return Query(sqlstr.Data());
279}
280
281////////////////////////////////////////////////////////////////////////////////
282
284{
285 CheckConnect("GetTablesList", nullptr);
286
287 TString cmd("SELECT table_name FROM user_tables");
288 if (wild && *wild)
289 cmd += TString::Format(" WHERE table_name LIKE '%s'", wild);
290
291 TSQLStatement* stmt = Statement(cmd);
292 if (!stmt) return nullptr;
293
294 TList *lst = nullptr;
295
296 if (stmt->Process()) {
297 stmt->StoreResult();
298 while (stmt->NextResultRow()) {
299 const char* tablename = stmt->GetString(0);
300 if (!tablename) continue;
301 if (!lst) {
302 lst = new TList;
303 lst->SetOwner(kTRUE);
304 }
305 lst->Add(new TObjString(tablename));
306 }
307 }
308
309 delete stmt;
310
311 return lst;
312}
313
314////////////////////////////////////////////////////////////////////////////////
315/// Produces SQL table info
316/// Object must be deleted by user
317
319{
320 CheckConnect("GetTableInfo", nullptr);
321
322 if (!tablename || (*tablename==0)) return nullptr;
323
324 TString table(tablename);
325 table.ToUpper();
326 TString sql;
327 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());
328
329 TSQLStatement* stmt = Statement(sql.Data(), 10);
330 if (!stmt) return nullptr;
331
332 if (!stmt->Process()) {
333 delete stmt;
334 return nullptr;
335 }
336
337 TList *lst = nullptr;
338
339 stmt->StoreResult();
340
341 while (stmt->NextResultRow()) {
342 const char* columnname = stmt->GetString(0);
343 TString data_type = stmt->GetString(1);
344 Int_t data_length = stmt->GetInt(2); // this is size in bytes
345 Int_t data_precision = stmt->GetInt(3);
346 Int_t data_scale = stmt->GetInt(4);
347 const char* nstr = stmt->GetString(5);
348 Int_t char_col_decl_length = stmt->GetInt(6);
349 Int_t data_sign = -1; // no info about sign
350
351 Int_t sqltype = kSQL_NONE;
352
353 if (data_type=="NUMBER") {
354 sqltype = kSQL_NUMERIC;
355 if (data_precision<=0) {
356 data_precision = -1;
357 data_scale = -1;
358 } else
359 if (data_scale<=0)
360 data_scale = -1;
361 data_sign = 1;
362 } else
363
364 if (data_type=="CHAR") {
365 sqltype = kSQL_CHAR;
366 data_precision = char_col_decl_length;
367 data_scale = -1;
368 } else
369
370 if ((data_type=="VARCHAR") || (data_type=="VARCHAR2")) {
371 sqltype = kSQL_VARCHAR;
372 data_precision = char_col_decl_length;
373 data_scale = -1;
374 } else
375
376 if (data_type=="FLOAT") {
377 sqltype = kSQL_FLOAT;
378 data_scale = -1;
379 if (data_precision==126) data_precision = -1;
380 data_sign = 1;
381 } else
382
383 if (data_type=="BINARY_FLOAT") {
384 sqltype = kSQL_FLOAT;
385 data_scale = -1;
386 data_precision = -1;
387 data_sign = 1;
388 } else
389
390 if (data_type=="BINARY_DOUBLE") {
391 sqltype = kSQL_DOUBLE;
392 data_scale = -1;
393 data_precision = -1;
394 data_sign = 1;
395 } else
396
397 if (data_type=="LONG") {
398 sqltype = kSQL_VARCHAR;
399 data_length = 0x7fffffff; // size of LONG 2^31-1
400 data_precision = -1;
401 data_scale = -1;
402 } else
403
404 if (data_type.Contains("TIMESTAMP")) {
405 sqltype = kSQL_TIMESTAMP;
406 data_precision = -1;
407 }
408
409 Bool_t IsNullable = kFALSE;
410 if (nstr)
411 IsNullable = (*nstr=='Y') || (*nstr=='y');
412
413 TSQLColumnInfo* info =
414 new TSQLColumnInfo(columnname,
415 data_type,
416 IsNullable,
417 sqltype,
418 data_length,
419 data_precision,
420 data_scale,
421 data_sign);
422
423 if (!lst) lst = new TList;
424 lst->Add(info);
425 }
426
427 delete stmt;
428
429 return new TSQLTableInfo(tablename, lst);
430}
431
432////////////////////////////////////////////////////////////////////////////////
433/// List all columns in specified table in the specified database.
434/// Wild is for wildcarding "t%" list all columns starting with "t".
435/// Returns a pointer to a TSQLResult object if successful, 0 otherwise.
436/// The result object must be deleted by the user.
437
438TSQLResult *TOracleServer::GetColumns(const char * /*dbname*/, const char *tablename,
439 const char * wild)
440{
441 CheckConnect("GetColumns", nullptr);
442
443// make no sense, while method is not implemented
444// if (SelectDataBase(dbname) != 0) {
445// SetError(-1, "Database is not connected","GetColumns");
446// return nullptr;
447// }
448
449 TString sql;
450 TString table(tablename);
451 table.ToUpper();
452 if (wild && *wild)
453 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);
454 else
455 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());
456 return Query(sql);
457}
458
459////////////////////////////////////////////////////////////////////////////////
460/// Select a database. Returns 0 if successful, non-zero otherwise.
461/// NOT IMPLEMENTED.
462
463Int_t TOracleServer::SelectDataBase(const char * /*dbname*/)
464{
465 CheckConnect("SelectDataBase", -1);
466
467 // do nothing and return success code
468 return 0;
469}
470
471////////////////////////////////////////////////////////////////////////////////
472/// List all available databases. Wild is for wildcarding "t%" list all
473/// databases starting with "t".
474/// Returns a pointer to a TSQLResult object if successful, 0 otherwise.
475/// The result object must be deleted by the user.
476/// NOT IMPLEMENTED.
477
479{
480 CheckConnect("GetDataBases", nullptr);
481
482 return nullptr;
483}
484
485////////////////////////////////////////////////////////////////////////////////
486/// Create a database. Returns 0 if successful, non-zero otherwise.
487/// NOT IMPLEMENTED.
488
489Int_t TOracleServer::CreateDataBase(const char * /*dbname*/)
490{
491 CheckConnect("CreateDataBase",-1);
492
493 return -1;
494}
495
496////////////////////////////////////////////////////////////////////////////////
497/// Drop (i.e. delete) a database. Returns 0 if successful, non-zero
498/// otherwise.
499/// NOT IMPLEMENTED.
500
501Int_t TOracleServer::DropDataBase(const char * /*dbname*/)
502{
503 CheckConnect("DropDataBase",-1);
504
505 return -1;
506}
507
508////////////////////////////////////////////////////////////////////////////////
509/// Reload permission tables. Returns 0 if successful, non-zero
510/// otherwise. User must have reload permissions.
511/// NOT IMPLEMENTED.
512
514{
515 CheckConnect("Reload", -1);
516
517 return -1;
518}
519
520////////////////////////////////////////////////////////////////////////////////
521/// Shutdown the database server. Returns 0 if successful, non-zero
522/// otherwise. User must have shutdown permissions.
523/// NOT IMPLEMENTED.
524
526{
527 CheckConnect("Shutdown", -1);
528
529 return -1;
530}
531
532////////////////////////////////////////////////////////////////////////////////
533/// Return Oracle server version info.
534
536{
537 CheckConnect("ServerInfo", nullptr);
538
539 fInfo = "Oracle";
540 TSQLStatement* stmt = Statement("select * from v$version");
541 if (stmt) {
543 if (stmt->Process()) {
544 fInfo = "";
545 stmt->StoreResult();
546 while (stmt->NextResultRow()) {
547 if (fInfo.Length()>0) fInfo += "\n";
548 fInfo += stmt->GetString(0);
549 }
550 }
551 delete stmt;
552 }
553
554 return fInfo.Data();
555}
556
557////////////////////////////////////////////////////////////////////////////////
558/// Call Commit() to submit all chanes, done before.
559/// Commit() ot Rollback() must be used to complete submitted actions or cancel them
560
562{
563 return Commit();
564}
565
566////////////////////////////////////////////////////////////////////////////////
567/// Commits all changes made since the previous Commit() or Rollback()
568/// Return kTRUE if OK
569
571{
572 CheckConnect("Commit", kFALSE);
573
574 try {
575 fConn->commit();
576 return kTRUE;
577 } CatchError("Commit")
578
579 return kFALSE;
580}
581
582////////////////////////////////////////////////////////////////////////////////
583/// Drops all changes made since the previous Commit() or Rollback()
584/// Return kTRUE if OK
585
587{
588 CheckConnect("Rollback", kFALSE);
589
590 try {
591 fConn->rollback();
592 return kTRUE;
593 } CatchError("Rollback")
594
595 return kFALSE;
596}
597
598////////////////////////////////////////////////////////////////////////////////
599/// set format for converting timestamps or date field into string
600/// default value is "MM/DD/YYYY, HH24:MI:SS"
601
603{
604 if (!fmt) fmt = "MM/DD/YYYY, HH24:MI:SS";
605 fgDatimeFormat = fmt;
606}
607
608////////////////////////////////////////////////////////////////////////////////
609/// return value of actual conversion format from timestamps or date to string
610
612{
613 return fgDatimeFormat;
614}
constexpr Bool_t kFALSE
Definition RtypesCore.h:101
constexpr Ssiz_t kNPOS
Definition RtypesCore.h:124
constexpr Bool_t kTRUE
Definition RtypesCore.h:100
const char Option_t
Definition RtypesCore.h:66
#define ClassImp(name)
Definition Rtypes.h:377
#define CheckConnect(method, res)
#define CatchError(method)
Int_t gDebug
Definition TROOT.cxx:585
virtual void SetOwner(Bool_t enable=kTRUE)
Set whether this collection is the owner (enable==true) of its content.
A doubly linked list.
Definition TList.h:38
void Add(TObject *obj) override
Definition TList.h:81
Collectable string class.
Definition TObjString.h:28
void MakeZombie()
Definition TObject.h:53
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition TObject.cxx:944
static void SetDatimeFormat(const char *fmt="MM/DD/YYYY, HH24:MI:SS")
set format for converting timestamps or date field into string default value is "MM/DD/YYYY,...
oracle::occi::Connection * fConn
TSQLResult * GetTables(const char *dbname, const char *wild=nullptr) final
List all tables in the specified database.
Int_t DropDataBase(const char *dbname) final
Drop (i.e.
Int_t Shutdown() final
Shutdown the database server.
TSQLResult * GetColumns(const char *dbname, const char *table, const char *wild=nullptr) final
List all columns in specified table in the specified database.
static const char * fgDatimeFormat
TSQLStatement * Statement(const char *sql, Int_t niter=100) final
Bool_t StartTransaction() final
Call Commit() to submit all chanes, done before.
~TOracleServer()
Close connection to Oracle DB server.
Bool_t Commit() final
Commits all changes made since the previous Commit() or Rollback() Return kTRUE if OK.
void Close(Option_t *opt="") final
Close connection to Oracle DB server.
Bool_t Rollback() final
Drops all changes made since the previous Commit() or Rollback() Return kTRUE if OK.
const char * ServerInfo() final
Return Oracle server version info.
TSQLResult * Query(const char *sql) final
Execute SQL command.
Bool_t Exec(const char *sql) final
Execute sql command which does not produce any result set.
TList * GetTablesList(const char *wild=nullptr) final
Return list of user tables Parameter wild specifies wildcard for table names.
TSQLTableInfo * GetTableInfo(const char *tablename) final
Produces SQL table info Object must be deleted by user.
Int_t CreateDataBase(const char *dbname) final
Create a database.
TSQLResult * GetDataBases(const char *wild=nullptr) final
List all available databases.
static const char * GetDatimeFormat()
return value of actual conversion format from timestamps or date to string
oracle::occi::Environment * fEnv
Bool_t IsConnected() const final
Int_t Reload() final
Reload permission tables.
Int_t SelectDataBase(const char *dbname) final
Select a database.
TOracleServer(const TOracleServer &)=delete
format for converting date and time stamps into string
void ClearError()
reset error fields
TString fHost
Definition TSQLServer.h:45
void SetError(Int_t code, const char *msg, const char *method=nullptr)
set new values for error fields if method is specified, displays error message
Int_t fPort
Definition TSQLServer.h:47
Bool_t fErrorOut
Definition TSQLServer.h:50
TString fDB
Definition TSQLServer.h:46
TString fType
Definition TSQLServer.h:44
virtual void EnableErrorOutput(Bool_t on=kTRUE)
virtual const char * GetString(Int_t)
virtual Bool_t NextResultRow()=0
virtual Int_t GetInt(Int_t)
virtual Bool_t Process()=0
virtual Bool_t StoreResult()=0
Basic string class.
Definition TString.h:139
Ssiz_t Length() const
Definition TString.h:421
const char * Data() const
Definition TString.h:380
void ToUpper()
Change string to upper case.
Definition TString.cxx:1183
static TString Format(const char *fmt,...)
Static method which formats a string using a printf style format descriptor and return a TString.
Definition TString.cxx:2356
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition TString.cxx:2334
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition TString.h:636
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition TString.h:651
This class represents a WWW compatible URL.
Definition TUrl.h:33
const char * GetFile() const
Definition TUrl.h:69
Bool_t IsValid() const
Definition TUrl.h:79
const char * GetHost() const
Definition TUrl.h:67
const char * GetOptions() const
Definition TUrl.h:71
const char * GetProtocol() const
Definition TUrl.h:64
Int_t GetPort() const
Definition TUrl.h:78