Commit c810090b authored by cvs2svn's avatar cvs2svn
Browse files

This commit was manufactured by cvs2svn to create tag 'COOL_0_0_3-pre1'.

git-svn-id: file:///git/lcgcool.svndb/cool/tags/COOL_0_0_3-pre1@798 4525493e-7705-40b1-a816-d608a930855b
parent a6c23b21
<include_path path=.></include_path>
<use name=CoolKernel>
# Dependency on POOL RelationalAccess (implies some SEAL dependencies) - RAL
# Dependency on SEAL SealServices - Application
# Dependency on SEAL SealUtils - SealTimer
<external ref=POOL use=RelationalAccess></external>
<external ref=SEAL use=Framework/SealServices></external>
<external ref=SEAL use=Foundation/SealUtil></external>
<export autoexport=true>
<lib name=lcg_RelationalCool>
# This provides at least one plugin
PLUGIN_MODULE := RelationalCool
# Disable multithreading as it gives problems with MySQL/ODBC on RH73
<Architecture name=rh73_gcc323>
<Architecture name=rh73_gcc32>
// $Id: RalDatabaseSvcFactory.h,v 1.3 2004-12-09 10:22:18 avalassi Exp $
namespace cool
// Forward declarations
class IDatabaseSvc;
** NB: this class should only be used in _STANDALONE_ applications **
** where a SEAL Context is not explicitly instantiated by the user. **
* @class RalDatabaseSvcFactory RalDatabaseSvcFactory.h
* Factory of standalone RalDatabaseSvc instances.
* The factory implementation takes care to instantiate a SEAL context
* and retrieve the RalDatabaseSvc plugin dynamically within the context.
* The SEAL context where the service is defined is a singleton
* owned by the factory class: the same service would be returned
* by successive calls to the getService method.
* @author Andrea Valassi and Sven A. Schmidt
* @date 2004-12-08
class RalDatabaseSvcFactory {
/// Locate the COOL database service in a standalone singleton SEAL context
static IDatabaseSvc& getDatabaseService();
// $Id: RalDatabaseSvcLabel.h,v 1.1 2004-11-11 08:49:48 avalassi Exp $
namespace cool
static const
char RalDatabaseSvcLabel[] = "COOL/KernelServices/RalDatabaseSvc";
// $Id: RelationalException.h,v 1.9 2005-01-14 14:09:53 sas Exp $
// Include files
#include "CoolKernel/Exception.h"
namespace cool
/** @class RelationalException RelationalException.h
* Base exception class for the relational implementations of COOL.
* Derived from SEAL Exception just like the POOL RelationalException.
* @author Andrea Valassi and Sven A. Schmidt
* @date 2004-11-10
class RelationalException : public Exception {
/// Constructor
RelationalException( const std::string& message,
const std::string& methodName );
/// Copy constructor
RelationalException( const RelationalException& rhs );
/// Destructor
virtual ~RelationalException() throw() {};
/// Clone method
virtual seal::Exception* clone() const;
/** @class RelationalDatabaseNotOpen
* Exception thrown when a database is not open.
class RelationalDatabaseNotOpen : public RelationalException {
/// Constructor
explicit RelationalDatabaseNotOpen( const std::string& methodName ) :
RelationalException( "The database is not open",
methodName ) {};
/// Destructor
virtual ~RelationalDatabaseNotOpen() throw() {};
/** @class RelationalDatabaseDoesNotExist
* Exception thrown when a database does not exist.
class RelationalDatabaseDoesNotExist : public RelationalException {
/// Constructor
explicit RelationalDatabaseDoesNotExist( const std::string& methodName ) :
RelationalException( "The database does not exist",
methodName ) {};
/// Destructor
virtual ~RelationalDatabaseDoesNotExist() throw() {};
/** @class RelationalFolderExists
* Exception thrown during folder creation when a folder already exists.
class RelationalFolderExists : public RelationalException {
/// Constructor
explicit RelationalFolderExists( const std::string& fullPath,
const std::string& methodName ) :
RelationalException( "Folder[set] " + fullPath + " already exists",
methodName ) {};
/// Destructor
virtual ~RelationalFolderExists() throw() {};
/** @class RelationalFolderNotFound
* Exception thrown when a folder does not exist.
class RelationalFolderNotFound : public RelationalException {
/// Constructor
explicit RelationalFolderNotFound( const std::string& fullPath,
const std::string& methodName ) :
RelationalException( "Folder[set] " + fullPath + " not found",
methodName ) {};
/// Destructor
virtual ~RelationalFolderNotFound() throw() {};
/** @class RelationalObjectNotFound
* Exception thrown when an object does not exist.
class RelationalObjectNotFound : public RelationalException {
/// Constructor
explicit RelationalObjectNotFound( const std::string& pointInTime,
const std::string& objectTableName,
const std::string& methodName ) :
RelationalException( "Object at " + pointInTime + " not found " +
"in " + objectTableName,
methodName ) {};
/// Destructor
virtual ~RelationalObjectNotFound() throw() {};
// $Id: ValidityKeyException.h,v 1.1 2004-12-06 20:33:44 avalassi Exp $
// Include files
#include "CoolKernel/Exception.h"
#include "CoolKernel/IValidityKey.h"
namespace cool
/** @class ValidityKeyException ValidityKeyException.h
* Base exception class for validity key exceptions in COOL.
* Derived from SEAL Exception just like the POOL RelationalException.
* @author Andrea Valassi and Sven A. Schmidt
* @date 2004-12-06
class ValidityKeyException : public Exception {
/// Constructor
ValidityKeyException( const std::string& message,
const std::string& methodName );
/// Copy constructor
ValidityKeyException( const ValidityKeyException& rhs );
/// Destructor
virtual ~ValidityKeyException() throw() {};
/// Clone method
virtual seal::Exception* clone() const;
/** @class ValidityKeyOutOfBoundaries
* Exception thrown when validity key is too low or too high.
class ValidityKeyOutOfBoundaries : public ValidityKeyException {
/// Constructor
explicit ValidityKeyOutOfBoundaries( const IValidityKey& key,
const std::string& methodName );
/// Destructor
virtual ~ValidityKeyOutOfBoundaries() throw() {};
/** @class ValidityIntervalBackwards
* Exception thrown when since > until in a validity interval.
class ValidityIntervalBackwards : public ValidityKeyException {
/// Constructor
explicit ValidityIntervalBackwards( const IValidityKey& since,
const IValidityKey& until,
const std::string& methodName );
/// Destructor
virtual ~ValidityIntervalBackwards() throw() {};
// $Id: timeToString.h,v 1.3 2004-12-14 10:30:30 avalassi Exp $
// Include files
#include <sstream>
#include <string>
#include <stdio.h>
#include "CoolKernel/Exception.h"
#include "SealBase/Time.h"
namespace cool {
/// Convert a string date "yyyy-mm-dd_hh:mm:ss.nnnnnnnnn into a seal::Time.
/// The format is the one we used to store dates for both Oracle and MySQL.
inline const seal::Time stringToTime( const std::string timeString )
int year, month, day, hour, min, sec;
long nsec;
if ( timeString.size() ==
std::string( "yyyy-mm-dd_hh:mm:ss.nnnnnnnnn" ).size()
&& sscanf( timeString.c_str(), "%4d-%2d-%2d_%2d:%2d:%2d.%9ld",
&year, &month, &day, &hour, &min, &sec, &nsec) == 7
&& timeString.substr(4,1) == "-"
&& timeString.substr(7,1) == "-"
&& timeString.substr(10,1) == "_"
&& timeString.substr(13,1) == ":"
&& timeString.substr(16,1) == ":"
&& timeString.substr(19,1) == "." ) {
bool local = true;
month -= 1; // Months in [0-11]
seal::Time time( year, month, day,
hour, min, sec, (seal::Time::ValueType)nsec, local );
return time;
} else {
std::string msg = "Error decoding string into seal::Time: ";
msg += timeString;
throw cool::Exception( msg, "cool::stringToTime" );
/// Convert seal::Time into a string in the format expected by stringToTime.
/// Useful to print seal::Time (the default operator<< uses a weird format).
inline const std::string timeToString( const seal::Time& time )
bool local = true;
int year = time.year( local );
int month = time.month( local ) + 1; // Months are in [0-11]
int day = local );
int hour = time.hour( local );
int min = time.minute( local );
int sec = time.second( local );
long nsec = time.nsecond();
char timeString[] = "yyyy-mm-dd_hh:mm:ss.nnnnnnnnn";
int nChar = std::string(timeString).size();
if ( sprintf( timeString, "%4.4d-%2.2d-%2.2d_%2.2d:%2.2d:%2.2d.%9.9ld",
year, month, day, hour, min, sec, nsec) == nChar ) {
return std::string(timeString);
} else {
std::ostringstream msg;
msg << "Error encoding seal::Time into string: " << time;
throw cool::Exception( msg.str(), "cool::timeToString" );
AV's plan for cleaning up the code - 14.12.2004
General ideas:
- Need three or more types of classes, Relational, Ral, Hvs;
for the moment they can stay all in RelationalCool, then we can move them
- Hvs for the moment is only needed to model transient HVS entities
and factor out functionality that is implemented by CondDB stuff too
(eg HvsNode should be - again - a base clas for RelationalFolder)
- Relational classes should contain all the table and column names
and all the algorithmic logic of the relational implementation
- Ral classes should contain only the code that really does table
creation/dropping and row insertion/update/select/delete: the idea
is that one can provide a MySQL or OCCI direct implementation of
the Relational conddb by JUST replacing the Ral classes
==> Main emphasis of this round of cleanup should be to extract out of
the Ral classes the functionality that belongs to Relational
Specific points for Ral classes
- RalDatabaseSvc: OK should remain
- RalDatabaseSvcFactory: OK for now... eventually may be replaced
by a more general DatabaseSvcFactory, which should understand
IDs of the form "ral::mysql:/" or "mysql::mysql:/" and instantiate
a Ralor MySQL database service to handle the same mysql database....
- RalTransaction: should disappear, it should become RelationalTransaction.
The idea is that the user does not manipulate transactions.
All methoids called by the user are encapsulated within a transaction.
Typically, these methods have the form { 1.startTransaction
2.doSomethingInDb 3.commitTransaction }. Such methods should
go to the Relational classes. In particular, startTransaction and
commitTransaction should be achieved withRelationalTransaction, eg
RelationalTransaction transaction( m_db );
... interpret the row and return the object ...
RelationalTransaction( RelationalDatabase* db ) {
db->startTransaction( this );
The RalDatabase, ie the only Ral aware class, is the one that both
fetches the object and actually starts the transaction:
virtual RelationalDatabase startTransaction( RelationalTransaction t ) = 0;
virtual RelationalDatabase fetchRow(...) = 0;
RalDatabase::startTransaction( RelationalTransaction t ) {
t.setStarted(); // JUST SETS A FLAG...
RalDatabase::fetchRow(...) {
Forcing the startTransaction method to accept a RelationalTransaction
argument binds the startTransaction to a particular transaction instance,
so that one is not just tempted to call startTransaction instead
of writing "RelationalTransaction t" in the method where t is started.
Eventually, note that RDBMS offer the possibility to start transacions
with a name, so as to have several concurrent isolated transactions
in the same session... passing the argument can just pass the name...
- RalSequence: this should also change as RelationalSequence.
Again, RalDatabase should take care of doing the actual insert/delete
and so on in the database....
I would keep this for quite a while, because I am not sure when
RAL will support native sequences, or provide SYSDATE support.
Eventually one may think of having all sequences in the same table,
each sequence in a separate row, to have fewer tables.
- RalDatabase: this should be the ONLY Ral class (apart from the
databasesvc and its factory) that remains.
NB: for the moment, the methods it is answeriung are of the form
'fetch object from object table with that order'...
Eventually, this could be refactored slightly so that it offers
much higher level services, eg generic table handling, BUT
- we dont want to reinvent RAL
- somewhere the specific choices of how to write the queries in SQL
(eg the order of inserting the arguments) must be made,
and it should be in the RAL specific class
Other points:
- Should make much more uniform the treatment of the various tables
in the code, have a uniform look and feel for defining the column
names and column types. We may think of using typedefs for the
column types (in the static declarations), so that the code is not
forced to make assumptions in setValue/getValue (eg if IValidityKey
is declared as long long but the iovSince column is typedefed
temporarily as long, the code can be written without knowing
that the iovSince is long... it will just force a conversion
from IValidityKey to/from iovSince type, whatever that is)
- It may be (??) useful to have a table class, and derive all
tables that are present in our code from that class.
But not sure, what would this gain exactly?
Maybe we can let RalDatabase handle the base table, and then automatically
all derived tables by inheritance?
- Instead/in any case, it may be useful to split out the various
'namespaces' RelationalObjectTable, RelationalFolderTable and so on
as real classes RelationalObjectTable, RelationalFolderTable, and so on.
Definitely (again!), the look and feel should be more harmonious,
eg column definitions for RelationalObjectTable in file
RelationalObject.h, or RelationalObjectTable.h, not moving
from RalDatabase.h to RelationalDatabase.h and so on...
- Iterators
Eventually these should become real iterators which retrieve rows in bulk,
say 1000 by 1000, but not N millions rows all together if this is what is
in the table and in the iteration loop. For this reason it should
only have forward iteration. "Freezing" of the database
can be achived by only selecting rows whose insertion time,
or update time, is less than the time at which the iterator
was created....
The number of rows fetched in each roundtrip may be set by the user,
but it may also be an internal detail at the beginning.
That is to say: the initial implementation of the iterator
now returns an ObjectVectorIterator, but eventually
it should return something more complex!
- Update time
The feature outlined above needs an extra "update time" column
that should be changed when for instance the online columns
has +infinity transformed into a real time.
Note that also in the versioning mode you will have the need
for updating the rows (eg "HEAD unti objectId..." column).
// $Id: RAL_feedback.txt,v 1.10 2004-12-06 20:32:22 avalassi Exp $
* AttributeList definitions for seal::LongLong and seal::Time
AttributeLists are not defined for these types.
I cannot create columns with these types...
* Transaction settings
Oracle readonly transaction uses READ ONLY rather than SERIALIZABLE.
This gets ORA-01466 which is probably an Oracle bug.
Anyway, we should define what transaction mechanism we really want!
Serializable looks safer and better than readonly, but it may block
concurrent users from running at the same time.
* SYSDATE date computed by the server
RAL does not offer a way to specify that SYSDATE should be used
in the SQL insert statement.
* AttributeList copy constructor and assignment operator
AttributeLists behave differently depending on whether they were built
from a reference or a boost shared pointer specification.
The assignment operator is reliable only in the second case.
The copy constructor gives problems for both.
This was notified to Kuba, Ioannis and Rado.
* Set clause syntax for MySQL/ODBC in IRelationalTableDataEditor::updateRows
Oracle requires ":bindvariable", MySQL/ODBC requires "?".
Rado is aware of this and fixed it in his version of the code.
==> Wait till is publicly available and change the COOL code accordingly
(list of files: RalSequence.cpp).
* Multi-threading problems with MySQL/ODBC
I had to disable the -pthread switch on RelationalCool because
the application hangs (only for MySQL). The circumstances are
difficult to explain exactly: it happens in RalSequence when
I try to drop a table and then recreate it again. It does not
happen if the table had been dropped using TOra...
Rado is aware of the problem, it may be solved by the next driver of MyODBC.
==> Wait till POOL is built using the new driver and test it
(list of files: RelationalCoool/BuildFile).
RAL does not offer a way to compute ANALYZE TABLE COMPUTE STATISTICS.
Note that also MySQL has the ANALYZE TABLE command.
* Partitioning and local indexes
RAL does not offer a way to use table partitioning and local indexes.
* Problem inserting rows where all values are NULL
This is translated into non-valid SQL:
I told Ioannis and Rado about this.
==> Can survive for the moment, change code if Ioannis fixes this eventually
* Feature with columnNamesAndTypes()
If you insert a column via insertColumn( columnName, typeName )
and then retrieve columnNamesAndTypes(), the types are not guaranteed
to be the same. For instance, insertColumn for "unsigned long" will
return an "unsigned long" on MySQL (as the native type can be mapped),
while it will return "long" on Oracle because this maps to NUMBER(38).
This causes problems if you try to then insert an attribute value via
setValue<type> into the attribute list, pool::attribute_bad_type
will be thrown.
=> Solution: when filling in the table, do not rely on columnNamesAndTypes():
instead, keep a local copy of the C++ mapping in the tables or in the
C++ code! This solves the setValue() problem.
* Feature with IRelationalCursor::currentRow()
Also in this case the same problem appears: the attribute list returned
has a specification that is read from the table description, ie exactly
the same returned by columnNamesAndTypes(). If the previous problem
appeared for setValue(), this appears for getValue(): it is a priory
impossible to know which C++ should be used for getValue(). The only
safe one is string, but this is not satisfactory!
=> Solution: you must use defineOutput() to specify the required format!
* NULL values inserted in MySQL third column (POOL_1_8_0)
This is fixed in the HEAD of ODBCAccess since december 3.
There was a bug with the use of STL vectors: push_back changes
the internal memory addresses of all vector elements.