ATLAS Offline Software
Loading...
Searching...
No Matches
CoraCoolDatabase.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
5// CoraCoolDatabase.cxx
6// implematation for CoraCoolDatabase
7// Richard Hawkings, started 10/06
8
9#include "CoralBase/AttributeSpecification.h"
10#include "CoralBase/AttributeList.h"
11#include "CoralBase/Attribute.h"
12#include "CoralBase/Exception.h"
13#include "RelationalAccess/IConnectionService.h"
14#include "RelationalAccess/ISessionProxy.h"
15#include "RelationalAccess/ITable.h"
16#include "RelationalAccess/TableDescription.h"
17#include "RelationalAccess/ITableDataEditor.h"
18#include "RelationalAccess/ITransaction.h"
19#include "RelationalAccess/ISchema.h"
20#include "RelationalAccess/IQuery.h"
21#include "RelationalAccess/ICursor.h"
22#include "RelationalAccess/SchemaException.h"
23
24#include "CoolKernel/IFolder.h"
25#include "CoolKernel/IFieldSpecification.h"
26#include "CoolKernel/FolderSpecification.h"
27
29#include "CoraCoolSequence.h"
31
33
35
36// constructor with external COOL database reference
37CoraCoolDatabase::CoraCoolDatabase(const std::string& dbconn,
38 cool::IDatabasePtr cooldb,
39 coral::IConnectionService& coralsvc,
40 const bool readonly) :
41 m_cooldb(std::move(cooldb)),
42 m_connected(false),
43 m_readonly(readonly),
44 m_coralsvc(coralsvc),
45 m_proxy(0),
46 m_log("CoraCool")
47{
48 if (!extractCoralConStr(dbconn)) {
49 m_log << coral::Error << "Cannot derive CORAL connection string from: "
50 << dbconn << coral::MessageStream::endmsg;
51 throw CoraCoolException("Bad connection string",
52 "CoraCoolDatabase::CoraCoolDatabase");
53 }
54 m_log << coral::Debug << "CORAL dbconnection string is: " << m_dbconn
55 << coral::MessageStream::endmsg;
56}
57
59 if (!m_connected) {
60 coral::AccessMode access=m_readonly ? coral::ReadOnly : coral::Update;
61 try {
62 m_proxy=m_coralsvc.connect(m_dbconn,access);
63 m_connected=true;
64 }
65 catch (std::exception& e) {
66 m_log << coral::Error << "Exception caught: " << e.what() <<
67 coral::MessageStream::endmsg;
68 m_connected=false;
69 }
70 }
71 return m_connected;
72}
73
75 if (m_connected) {
76 delete m_proxy;
77 m_connected=false;
78 }
79 return m_connected;
80}
81
82bool CoraCoolDatabase::extractCoralConStr(const std::string_view coolstr) {
83 // extract CORAL database string from COOL one
84 bool dbok=false;
85 // first check for initial colon - if so, technology-specific string
86 std::string::size_type c1=coolstr.find(':');
87 if (c1!=std::string::npos) {
88 std::string_view techno,server,schema;
89 techno=coolstr.substr(0,c1);
90 std::string::size_type c2;
91 c2=coolstr.find(';');
92 if (c2==std::string::npos) c2=coolstr.size();
93 server=coolstr.substr(c1+3,c2-c1-3);
94 c1=coolstr.find("schema=");
95 if (c1!=std::string::npos) {
96 c2=coolstr.find(';',c1+7);
97 if (c2==std::string::npos) c2=coolstr.size();
98 schema=coolstr.substr(c1+7,c2-c1-7);
99 }
100 c1=coolstr.find("dbname=");
101 if (c1!=std::string::npos) {
102 c2=coolstr.find(';',c1+7);
103 if (c2==std::string::npos) c2=coolstr.size();
104 m_dbname=std::string(coolstr.substr(c1+7,c2-c1-7));
105 }
106 // construct the connection string
107 if (techno=="oracle" || techno=="mysql" || techno=="frontier") {
108 if (!server.empty() && !schema.empty()) {
109 m_dbconn=std::string(techno);
110 m_dbconn+= "://";
111 m_dbconn+=server;
112 m_dbconn+='/';
113 m_dbconn+=schema;
114 dbok=true;
115 }
116 } else if (techno=="sqlite") {
117 if (!schema.empty()) {
118 m_dbconn="sqlite_file:";
119 m_dbconn+=schema;
120 dbok=true;
121 }
122 }
123 } else {
124 c1=coolstr.find('/');
125 if (c1!=std::string::npos) {
126 m_dbconn=std::string(coolstr.substr(0,c1));
127 m_dbname=std::string(coolstr.substr(c1+1));
128 dbok=true;
129 }
130 }
131 if (m_dbname.empty()) dbok=false;
132 m_log << coral::Debug << "Extracted CORAL connection string: " << m_dbconn
133 << " and database name: " << m_dbname << " with status " << dbok <<
134 coral::MessageStream::endmsg;
135 return dbok;
136}
137
139 const cool::IRecordSpecification& spec) {
140 std::string result="";
141 unsigned int n=spec.size();
142 for (unsigned int i=0;i<n;++i) {
143 const cool::IFieldSpecification& field=spec[i];
144 result+=field.name();
145 result+=':';
146 result+=field.storageType().name();
147 if (i<n-1) result+=',';
148 }
149 return result;
150}
151
152bool CoraCoolDatabase::storeSpec(const std::string& tablename,
153 const std::string& spec) {
154 m_log << coral::Debug << "Store AttrList specification for table " <<
155 tablename << " : " << spec <<coral::MessageStream::endmsg;
156 // first check for existance of table
157 const std::string attrtable=m_dbname+"_CORACOOLATTR";
158 coral::ITable* table;
159 try {
160 table=&(m_proxy->nominalSchema().tableHandle(attrtable));
161 }
162 catch (coral::SchemaException& e) {
163 m_log << coral::Debug << "Creating table " << attrtable << coral::MessageStream::endmsg;
164 coral::TableDescription tdesc(attrtable);
165 tdesc.setName(attrtable);
166 tdesc.insertColumn("NAME","string",31,false);
167 tdesc.insertColumn("ATTRSPEC","string",4000,false);
168 tdesc.setPrimaryKey("NAME");
169 table=&(m_proxy->nominalSchema().createTable(tdesc));
170 // pause for thought
171 m_proxy->transaction().commit();
172 sleep(1);
173 m_proxy->transaction().start(false);
174 table=&(m_proxy->nominalSchema().tableHandle(attrtable));
175 }
176 if (table==0) {
177 m_log << coral::Error << "No pointer to " << attrtable << coral::MessageStream::endmsg;
178 return false;
179 }
180 // now update table with specification
181 try {
182 coral::AttributeList data;
183 data.extend<std::string>("NAME");
184 data.extend<std::string>("ATTRSPEC");
185 data[0].data<std::string>()=tablename;
186 data[1].data<std::string>()=spec;
187 coral::ITableDataEditor& editor=table->dataEditor();
188 editor.insertRow(data);
189 }
190 catch (coral::SchemaException&e) {
191 m_log << coral::Error << "Could not insert " << tablename << " into "
192 << attrtable << " exception: " << e.what() <<
193 coral::MessageStream::endmsg;
194 return false;
195 }
196 return true;
197}
198
200 const std::string& coraltable,
201 const cool::IRecordSpecification& fkspec,
202 const cool::IRecordSpecification& payloadspec,
203 const std::string& coralfk,
204 const std::string& coralpk,
205 const std::string& description,
206 const cool::FolderVersioning::Mode mode,
207 const bool createParents) {
208
209 // check input parameters
210 if (coraltable.size()>18) throw CoraCoolException(
211 "CORAL tablename too long (max 18 chars)",
212 "CoraCoolDatabase::createFolder");
213 // encode the folder description string
214 // first remove any existing coracool string
215 std::string::size_type p1,p2;
216 std::string newdesc=description;
217 p1=description.find("<coracool>");
218 p2=description.find("</coracool>");
219 if (p1!=std::string::npos && p2!=std::string::npos) {
220 newdesc=description.substr(0,p1);
221 newdesc.append(description, p2+11);
222 }
223 // COOL foreign key column is name of COOL payload attribute
224 newdesc+="<coracool>";
225 newdesc+=coraltable;
226 newdesc+=':';
227 newdesc+=fkspec[0].name();
228 newdesc+=':';
229 newdesc+= coralfk;
230 newdesc+=':';
231 newdesc+=coralpk;
232 newdesc+="</coracool>";
233 m_log << coral::Debug << "Created new description: " << newdesc <<
234 coral::MessageStream::endmsg;
235
236 // check for rows in key generation table, create if needed
237 // start transaction here
238 connect();
239 m_proxy->transaction().start(false);
240 CoraCoolSequence seqfk(m_dbname,m_dbname+"_"+coraltable+"_FK",m_proxy,true);
241 if (coralfk!=coralpk)
242 CoraCoolSequence seqpk(m_dbname,m_dbname+"_"+coraltable+"_PK",m_proxy,true);
243
244 // endcode and store the attributelist specification in CORACOOLATTR table
245 if (!storeSpec(m_dbname+"_"+coraltable,
246 encodeAttrSpec(payloadspec)))
247 throw CoraCoolException("Cannot store payload specification",
248 "CoraCoolDatabase::createFolder");
249
250 // create CORAL table
251 try {
252 m_log << coral::Debug << "Generate CORAL table:" << coraltable <<
253 coral::MessageStream::endmsg;
254 coral::TableDescription tdesc("CoraCoolPayload");
255 tdesc.setName(m_dbname+"_"+coraltable);
256 for (unsigned int i=0;i<payloadspec.size();++i) {
257 const cool::IFieldSpecification& field=payloadspec[i];
258 int maxsize=field.storageType().maxSize();
259 if (field.storageType()==cool::StorageType::Blob64k) maxsize=0;
260 const std::string typen=coral::AttributeSpecification::typeNameForId(
261 field.storageType().cppType());
262 m_log << coral::Debug << "Insert column " << field.name() <<
263 " of type " << typen << std::endl;
264 tdesc.insertColumn(field.name(),typen,maxsize,false);
265 }
266 // declare primary key
267 tdesc.setPrimaryKey(coralpk);
268 // create separate index on FK if different
269 if (coralfk!=coralpk)
270 tdesc.createIndex(m_dbname+"_"+coraltable+"F",coralfk,false);
271
272 m_proxy->nominalSchema().createTable(tdesc);
273 m_proxy->transaction().commit();
274 m_log << coral::Debug << "Created coral table " << coral::MessageStream::endmsg;
275
276 // disconnect/reconnect to avoid connection problems
277 disconnect();
278 sleep(1);
279 connect();
280 }
281 catch (std::exception& e) {
282 // problem in table creation
283 throw CoraCoolException(e.what(),"CoraCoolDatabase::createFolder");
284 }
285
286 // create corresponding COOL folder
287 // this has to go after CORAL manipulations otherwise get problems
288 // with schema consistency
289 // disconnect/reconnect to COOL first in order to reset COOL
290 // avoiding problems due to the reset database connection
291 m_log << coral::Debug << "Disconnect/reconnect COOL connection" <<
292 coral::MessageStream::endmsg;
293 m_cooldb->closeDatabase();
294 m_cooldb->openDatabase();
295 m_log << coral::Debug << "Create COOL folder" << coolpath << coral::MessageStream::endmsg;
296
297 m_cooldb->createFolder(coolpath,
298 cool::FolderSpecification(mode,fkspec),newdesc,createParents);
299 m_log << coral::Debug << "Created COOL folder" << coral::MessageStream::endmsg;
300
301 // all structures created,
302 // generate return value by instantiating new folder
303 CoraCoolFolderPtr folder(new CoraCoolFolder(coolpath,
304 m_proxy, m_cooldb,this,m_log));
305 return folder;
306}
307
308
309CoraCoolFolderPtr CoraCoolDatabase::getFolder(const std::string& coolfolder) {
310 connect();
312 coolfolder,m_proxy,m_cooldb,this,m_log));
313 return folder;
314}
315
316bool CoraCoolDatabase::existsFolder(const std::string& coolfolder) {
317 // first check if the COOL folder exists
318 if (!m_cooldb->existsFolder(coolfolder)) {
319 return false;
320 } else {
321 // if it does, check the folder description finds a coracool tag
322 // note this does not check the CORACOOL table actually exists
323 cool::IFolderPtr folder=m_cooldb->getFolder(coolfolder);
324 std::string tablename,keycolcool,fkeycolcoral,pkeycolcoral;
325 return parseFolderDescription(folder->description(),tablename,
326 keycolcool,fkeycolcoral,pkeycolcoral);
327 }
328}
329
330bool CoraCoolDatabase::parseFolderDescription(const std::string& folderdesc,
331 std::string& tablename,
332 std::string& keycolcool,
333 std::string& fkeycolcoral,
334 std::string& pkeycolcoral) {
335 // parse the folder description string to extract CORAL table and FKs
336 // format <coracool>Table:COOL_key:CORAL_fkey:CORAL_pkey</coracool>
337 // if CORAL_pkey is missing, assumed to be same as CORAL_fkey
338 // return false for parsing problem or missing <coracool> specification
339 // otherwise set return arguments
340
341 // find <coracool> part of the description
342 std::string::size_type p1,p2,c1,c2,c3;
343 p1=folderdesc.find("<coracool>");
344 p2=folderdesc.find("</coracool>");
345 if (p1==std::string::npos || p2==std::string::npos) return false;
346 // find the two : separating the values
347 c1=folderdesc.find(':',p1+10);
348 if (c1==std::string::npos) return false;
349 c2=folderdesc.find(':',c1+1);
350 if (c2==std::string::npos) return false;
351
352 tablename=m_dbname;
353 tablename+= '_';
354 tablename.append(folderdesc,p1+10,c1-p1-10);
355 keycolcool=folderdesc.substr(c1+1,c2-c1-1);
356 fkeycolcoral=folderdesc.substr(c2+1,p2-c2-1);
357 // check for third colon to specify separate primary key
358 c3=folderdesc.find(':',c2+1);
359 if (c3!=std::string::npos) {
360 fkeycolcoral=folderdesc.substr(c2+1,c3-c2-1);
361 pkeycolcoral=folderdesc.substr(c3+1,p2-c3-1);
362 } else {
363 fkeycolcoral=folderdesc.substr(c2+1,p2-c2-1);
364 pkeycolcoral=fkeycolcoral;
365 }
366 return true;
367}
368
369bool CoraCoolDatabase::deleteFolder(const std::string& coolfolder) {
370 m_log << coral::Debug << "Deleting folder " << coolfolder << coral::MessageStream::endmsg;
371 std::string desc;
372 // get COOL folder and description
373 try {
374 cool::IFolderPtr folder=m_cooldb->getFolder(coolfolder);
375 desc=folder->description();
376 // delete the COOL folder
377 m_cooldb->dropNode(coolfolder);
378 }
379 catch (cool::Exception& e) {
380 throw CoraCoolException(e.what(),"CoraCoolDatabase::deleteFolder");
381 }
382 // extract the CORAL folder name
383 std::string tablename,keycolcool,fkeycolcoral,pkeycolcoral;
384 if (parseFolderDescription(desc,tablename,keycolcool,
385 fkeycolcoral,pkeycolcoral)) {
386 m_log << coral::Debug << "Drop CORAL payload table " << tablename
387 << coral::MessageStream::endmsg;
388 // drop the CORAL table
389 connect();
390 m_proxy->transaction().start(false);
391 m_proxy->nominalSchema().dropIfExistsTable(tablename);
392 // remove primary/foreign key rows from sequence table
393 CoraCoolSequence seqfk(m_dbname,tablename+"_FK",m_proxy);
394 seqfk.dropSeq();
395 if (fkeycolcoral!=pkeycolcoral) {
396 CoraCoolSequence seqpk(m_dbname,tablename+"_PK",m_proxy);
397 seqpk.dropSeq();
398 }
399 // remove the row from the CORACOOLATTR table
400 coral::AttributeList bindvar;
401 bindvar.extend<std::string>("SNAME");
402 bindvar[0].data<std::string>()=tablename;
403 coral::ITable& table=m_proxy->nominalSchema().tableHandle(
404 m_dbname+"_CORACOOLATTR");
405 long rows=table.dataEditor().deleteRows("NAME=:SNAME",bindvar);
406 if (rows!=1) m_log << coral::Error << "Unexpected number of rows "
407 << rows << " with key " << tablename <<
408 " deleted from CORACOOLATTR table" << coral::MessageStream::endmsg;
409 m_proxy->transaction().commit();
410 // pause for thought
411 disconnect();
412 sleep(1);
413 connect();
414 }
415 return true;
416}
boost::shared_ptr< CoraCoolFolder > CoraCoolFolderPtr
char data[hepevt_bytes_allocation_ATLAS]
Definition HepEvt.cxx:11
Define macros for attributes used to control the static checker.
coral::IConnectionService & m_coralsvc
CoraCoolFolderPtr createFolder(const std::string &coolpath, const std::string &coraltable, const cool::IRecordSpecification &fkspec, const cool::IRecordSpecification &payloadspec, const std::string &coralfk, const std::string &coralpk, const std::string &description="", const cool::FolderVersioning::Mode mode=cool::FolderVersioning::SINGLE_VERSION, const bool createParents=false)
coral::ISessionProxy * m_proxy
coral::MessageStream m_log
bool extractCoralConStr(std::string_view coolstr)
CoraCoolDatabase(const std::string &m_dbconn, cool::IDatabasePtr cooldb, coral::IConnectionService &coralsvc, const bool readonly=false)
bool deleteFolder(const std::string &coolfolder)
CoraCoolFolderPtr getFolder(const std::string &coolfolder)
bool existsFolder(const std::string &coolfolder)
cool::IDatabasePtr m_cooldb
bool parseFolderDescription(const std::string &folderdesc, std::string &tablename, std::string &keycolcool, std::string &fkeycolcoral, std::string &pkeycolcoral)
std::string encodeAttrSpec(const cool::IRecordSpecification &spec)
bool storeSpec(const std::string &tablename, const std::string &spec)
std::string description
glabal timer - how long have I taken so far?
Definition hcg.cxx:91
STL namespace.