BOSS 8.0.0
BESIII Offline Software System
Loading...
Searching...
No Matches
Table.cxx
Go to the documentation of this file.
1// $Header: /bes/bes/BossCvs/Calibration/rdbModel/src/Tables/Table.cxx,v 1.1.1.1 2005/10/17
2// 06:10:53 maqm Exp $
3
4#include "rdbModel/Tables/Table.h"
5#include "facilities/Timestamp.h"
6#include "facilities/Util.h"
7#include "rdbModel/Db/Connection.h"
8#include "rdbModel/Db/ResultHandle.h"
9#include "rdbModel/RdbException.h"
10#include "rdbModel/Tables/Assertion.h"
11#include "rdbModel/Tables/Column.h"
12#include "rdbModel/Tables/Index.h"
13#include "rdbModel/Tables/InsertNew.h"
14#include "rdbModel/Tables/InterRow.h"
15#include "rdbModel/Tables/Query.h"
16#include "rdbModel/Tables/Set.h"
17#include "rdbModel/Tables/Supersede.h"
18#include <algorithm>
19
20namespace rdbModel {
22 : m_primaryKeyCol( "" )
23 , m_sorted( false )
24 , m_nEndUser( 0 )
25 , m_validRow( 0 )
26 , m_iNew( 0 )
27 , m_sup( 0 )
28 , m_connect( 0 ) {
29 m_sortedCols.clear();
30 m_programCols.clear();
31 m_userCols.clear();
32 m_mayDefault.clear();
33 m_out = &std::cout;
34 m_err = &std::cerr;
35 }
36
38 while ( m_cols.size() )
39 {
40 Column* c = m_cols.back();
41 m_cols.pop_back();
42 delete c;
43 }
44
45 while ( m_asserts.size() )
46 {
47 Assertion* a = m_asserts.back();
48 m_asserts.pop_back();
49 delete a;
50 }
51
52 while ( m_indices.size() )
53 {
54 Index* i = m_indices.back();
55 m_indices.pop_back();
56 delete i;
57 }
58 }
59
61 m_connect = connect;
62 m_out = connect->getOut();
63 m_err = connect->getErrOut();
64 }
65 // Columns are stored in order; binary cuts should do better than
66 // just dumb compare one by one.
67 Column* Table::getColumnByName( const std::string& name ) const {
68 unsigned nCol = m_sortedCols.size();
69 unsigned minI = 0;
70 unsigned maxI = nCol;
71
72 unsigned guess = maxI / 2;
73 unsigned oldGuess = nCol;
74
75 int cmp = name.compare( m_sortedCols[guess]->getName() );
76
77 while ( cmp != 0 )
78 {
79 if ( guess == oldGuess ) return 0; // not found
80
81 if ( cmp < 0 )
82 { // thing we tried is > colName, so decrease maxI
83 maxI = guess;
84 }
85 else
86 { // thing we tried is > colName, so increase minI
87 minI = guess;
88 }
89 oldGuess = guess;
90 guess = ( minI + maxI ) / 2;
91 cmp = name.compare( m_sortedCols[guess]->getName() );
92 }
93 return m_sortedCols[guess];
94 }
95
96 Index* Table::getIndexByName( const std::string& name ) const {
97 unsigned nIx = m_indices.size();
98 for ( unsigned iIx = 0; iIx < nIx; iIx++ )
99 {
100 Index* index = m_indices[iIx];
101 if ( index->getName() == name ) return index;
102 }
103 return 0;
104 }
105
106 Assertion* Table::getAssertionByName( const std::string& name ) const {
107 unsigned nAssert = m_asserts.size();
108 for ( unsigned i = 0; i < nAssert; i++ )
109 {
110 Assertion* a = m_asserts[i];
111 if ( a->getName() == name ) return a;
112 }
113 return 0;
114 }
115
116 // Traversal order is self, columns, indices, asserts
118
119 Visitor::VisitorState state = v->visitTable( this );
120 if ( state == Visitor::VBRANCHDONE ) return Visitor::VCONTINUE;
121 if ( state != Visitor::VCONTINUE ) return state;
122
123 unsigned n = m_cols.size();
124
125 for ( unsigned i = 0; i < n; i++ )
126 {
127 state = m_cols[i]->accept( v );
128 if ( state != Visitor::VCONTINUE ) return state;
129 }
130
131 n = m_indices.size();
132 for ( unsigned i = 0; i < n; i++ )
133 {
134 state = m_indices[i]->accept( v );
135 if ( state != Visitor::VCONTINUE ) return state;
136 }
137
138 n = m_asserts.size();
139 for ( unsigned i = 0; i < n; i++ )
140 {
141 state = m_asserts[i]->accept( v );
142 if ( state != Visitor::VCONTINUE ) return state;
143 }
144 return state;
145 }
146
148 if ( m_sorted ) return;
149 m_sortedCols = m_cols;
150
151 ColCompare cmpObject;
152
153 // Keep around original set so that rdbGUI will display them in
154 // this order
155 std::sort( m_sortedCols.begin(), m_sortedCols.end(), cmpObject );
156 m_sorted = true;
157 }
158
159 void Table::addColumn( Column* c ) {
160 m_cols.push_back( c );
162 {
163 m_nEndUser++;
164 // if not nullable and no default, user must supply it
165 if ( !( c->nullAllowed() ) && ( ( c->getDefault() ).size() == 0 ) )
166 { m_userCols.push_back( c ); }
167 else { m_mayDefault.push_back( c ); }
168 }
169 else if ( c->getSourceType() == Column::FROMdefault ) { m_mayDefault.push_back( c ); }
170 else if ( c->getSourceType() == Column::FROMprogram ) { m_programCols.push_back( c ); }
171 }
172
173 int Table::insertLatest( Row& row, int* serial ) const {
174
175 if ( !m_connect ) { throw RdbException( "Table::insertLatest Need matching connection" ); }
176 row.rowSort();
177
178 // Fill in columns in m_programCols list
179 fillProgramCols( row, true );
180
181 // Check that all required columns are there and not null
182 for ( unsigned i = 0; i < m_userCols.size(); i++ )
183 {
184 FieldVal* f = row.find( m_userCols[i]->getName() );
185 if ( ( !f ) || ( f->m_null ) )
186 {
187 std::string msg( "Table::insertLatest Row to be inserted missing req'd field " );
188 msg = msg + m_userCols[i]->getName();
189 throw RdbException( msg );
190 }
191 }
192 // Fill in defaults
193 fillDefaults( row );
194
195 // Check against consistency conditions specified by <insertNew>
196 const Assertion* cond = m_iNew->getInternal();
197 bool satisfied;
198
199 try
200 { satisfied = cond->verify( row, row ); } catch ( RdbException ex )
201 {
202 ( *m_out ) << ex.getMsg() << std::endl;
203 return -1;
204 }
205
206 if ( !satisfied ) return -1; // or maybe throw exception here?
207
208 // Check against official conditions specified by <insertNew>
209 const Assertion* condO = m_iNew->getOfficial();
210 Row empty;
211 std::vector<std::string> colNames;
212 std::vector<std::string> colValues;
213 std::vector<std::string> nullCols;
214
215 row.regroup( colNames, colValues, nullCols );
216
217 satisfied = condO->verify( empty, row );
218
219 // If not official, do insert and exit
220 if ( !satisfied )
221 {
222 bool ok = m_connect->insertRow( m_name, colNames, colValues, serial, &nullCols );
223 return ( ok ) ? 0 : -1;
224 }
225
226 const std::vector<InterRow*>& inter = m_iNew->getInterRow();
227
228 unsigned nInter = inter.size();
229 Assertion* subsAssert;
230 for ( unsigned iInter = 0; iInter < nInter; iInter++ )
231 {
232 const Query* q = inter[iInter]->getQuery();
233 const std::vector<std::string>& toSelect = q->getToSelect();
234
235 // Need to make a new Assertion which substitues our proposed row
236 // values for all "toBe" entries
237 subsAssert = new Assertion( q->getAssertion(), &row );
238
239 std::vector<std::string> orderCols;
240 orderCols.clear();
241 ResultHandle* r = m_connect->select( m_name, toSelect, orderCols, subsAssert );
242
243 if ( r->getNRows() == 0 )
244 { // no conflicts found
245 delete subsAssert;
246 continue; // go on to next InterRow, if any.
247 }
248
249 // otherwise
250 // if quit go ahead and quit
251 if ( inter[iInter]->getQuit() )
252 {
253 delete subsAssert;
254 ( *m_out ) << "insert latest not done because of irreconcilable " << std::endl
255 << "conflict with existing rows" << std::endl;
256 return -1;
257 }
258 // else modify conflicting rows as specified in <interRow>.
259 // (i.e., do an update with where clause = subsAssert
260
261 std::vector<Set> sets = inter[iInter]->getSets();
262
263 bool iu = doInterUpdate( sets, subsAssert, row );
264 if ( !iu ) return -1;
265 }
266 // Insert and exit
267 bool ok = m_connect->insertRow( m_name, colNames, colValues, serial, &nullCols );
268 return ( ok ) ? 0 : -1;
269 }
270
271 int Table::insertRow( Row& row, int* serial ) const {
272
273 if ( !m_connect ) { throw RdbException( "Table::insertRow Need matching connection" ); }
274 row.rowSort();
275
276 // Fill in columns in m_programCols list
277 fillProgramCols( row, true );
278
279 // Check that all required columns are there and not null
280 for ( unsigned i = 0; i < m_userCols.size(); i++ )
281 {
282 FieldVal* f = row.find( m_userCols[i]->getName() );
283 if ( ( !f ) || ( f->m_null ) )
284 {
285 std::string msg( "Table::insertRow Row to be inserted missing req'd field " );
286 msg = msg + m_userCols[i]->getName();
287 throw RdbException( msg );
288 }
289 }
290
291 // Fill in defaults
292 fillDefaults( row );
293
294 // Check standard valid row condition if there is one
295 if ( m_validRow )
296 {
297 bool satisfied;
298 try
299 { satisfied = m_validRow->verify( row, row ); } catch ( RdbException ex )
300 {
301 ( *m_out ) << ex.getMsg() << std::endl;
302 return -1;
303 }
304 if ( !satisfied )
305 {
306 // throw RdbException("Table::insertRow Row to be inserted is not valid");
307 ( *m_out ) << "Table::insertRow Row to be inserted is not valid " << std::endl;
308 m_out->flush();
309 return -1;
310 }
311 }
312 // Insert and exit
313 std::vector<std::string> colNames;
314 std::vector<std::string> colValues;
315 std::vector<std::string> nullCols;
316
317 row.regroup( colNames, colValues, nullCols );
318 bool ok = m_connect->insertRow( m_name, colNames, colValues, serial, &nullCols );
319 return ( ok ) ? 0 : -1;
320 }
321
322 int Table::supersedeRow( Row& row, int oldKey, int* serial ) const {
323 std::string oldKeyStr;
324 facilities::Util::itoa( oldKey, oldKeyStr );
325
326 if ( m_primaryKeyCol.size() == 0 )
327 { throw RdbException( "Table::supersedeRow No primary key column!" ); }
328
329 // Confirm that row does not contain any of the fixed or oldForced columns
330 row.rowSort();
331 const std::vector<std::string>& forced = m_sup->getForced();
332 for ( unsigned i = 0; i < forced.size(); i++ )
333 {
334 if ( row.find( forced[i] ) )
335 {
336 // throw RdbException
337 // (std::string("Table::supersedeRow bad column in input row ") +
338 // forced[i]);
339 ( *m_out ) << "Table::supersedeRow bad column in input row '" << forced[i] << "'"
340 << std::endl;
341 m_out->flush();
342 return -1;
343 }
344 }
345 const std::vector<FieldVal>& fixed = m_sup->getFixed();
346 for ( unsigned i = 0; i < fixed.size(); i++ )
347 {
348 if ( row.find( fixed[i].m_colname ) )
349 {
350 // throw RdbException
351 // (std::string("Table::supersedeRow bad column in input row ") +
352 // fixed[i].m_colname);
353 ( *m_out ) << "Table::supersedeRow bad column in input row " << fixed[i].m_colname;
354 m_out->flush();
355 return -1;
356 }
357 }
358
359 // Check that old row is supersedable
360 if ( !isSupersedable( oldKeyStr ) )
361 {
362 *m_out << "Row " << oldKey << " is not supersedable" << std::endl;
363 m_out->flush();
364 return -1;
365 }
366
367 // Fill in fixed fields
368 const std::vector<std::string>& fixedInterp = m_sup->getFixedInterp();
369 for ( unsigned i = 0; i < fixed.size(); i++ )
370 {
371
372 FieldVal fv = fixed[i];
373 if ( fixedInterp[i].size() > 0 )
374 {
375 Column* c = getColumnByName( fixed[i].m_colname );
376 c->interpret( fixedInterp[i], fv.m_val );
377 }
378 row.addField( fv );
379 }
380 row.rowSort();
381
382 // Fetch needed fields from row to be superseded (oldKey)
384 OPTYPEequal, m_primaryKeyCol, oldKeyStr, FIELDTYPEold, FIELDTYPElit );
385 Assertion* where = new Assertion( whereOp );
386
387 std::vector<std::string> noCols;
388 const std::vector<std::string>& fromOld = m_sup->getFromOld();
389 noCols.clear();
390 ResultHandle* results = m_connect->select( m_name, fromOld, noCols, where );
391 // std::vector<std::string> vals;
392 // results->getRow(vals);
393 std::vector<std::string*> vals;
394 results->getRowPtrs( vals );
395 // Merge as needed into our row. First bunch may already be in the row
396 unsigned nDef = m_sup->getOldDefaulted().size();
397 for ( unsigned i = 0; i < nDef; i++ )
398 {
399 if ( !( row.find( fromOld[i] ) ) )
400 {
401 if ( vals[i] == 0 ) { row.addField( FieldVal( fromOld[i], "", true ) ); }
402 else { row.addField( FieldVal( fromOld[i], *vals[i] ) ); }
403 row.rowSort();
404 }
405 }
406 // Remainder definitely have to be merged in
407 for ( unsigned i = nDef; i < fromOld.size(); i++ )
408 {
409 if ( vals[i] == 0 ) { row.addField( FieldVal( fromOld[i], "", true ) ); }
410 else { row.addField( FieldVal( fromOld[i], *vals[i] ) ); }
411 }
412 results->cleanFieldPtrs( vals );
413
414 // Insert the row and update old row
415 int insRet;
416 try
417 { insRet = insertRow( row, serial ); } catch ( RdbException ex )
418 {
419 ( *m_out ) << ex.getMsg() << std::endl;
420 insRet = -1;
421 }
422
423 if ( insRet )
424 { // something went wrong
425 delete where;
426 return insRet;
427 }
428
429 // Do the update of old row
430 const std::vector<Set*>& setOld = m_sup->getSetOld();
431 std::vector<FieldVal> oldFields;
432 oldFields.reserve( setOld.size() );
433 for ( unsigned i = 0; i < setOld.size(); i++ )
434 {
435 std::string src = setOld[i]->getSrcValue();
436 std::string col = setOld[i]->getDestColName();
437 if ( setOld[i]->hasInterp() )
438 {
439 Column* c = getColumnByName( col );
440 c->interpret( setOld[i]->getInterp(), src );
441 }
442 oldFields.push_back( FieldVal( col, src ) );
443 }
444 Row updateArg( oldFields );
445 try
446 {
447 int iUpdated = updateRows( updateArg, where );
448 if ( iUpdated == 1 ) return 0;
449 return -1;
450 } catch ( RdbException uEx )
451 {
452 ( *m_out ) << uEx.getMsg() << std::endl;
453 return -1;
454 }
455 }
456
457 int Table::updateRows( Row& row, Assertion* where ) const {
458
459 if ( !m_connect ) { throw RdbException( "Table::insertLatest Need matching connection" ); }
460 row.rowSort();
461
462 // Fill in columns in m_programCols list
463 fillProgramCols( row, false );
464
465 std::vector<std::string> colNames;
466 std::vector<std::string> colValues;
467 std::vector<std::string> nullCols;
468
469 row.regroup( colNames, colValues, nullCols );
470
471 return m_connect->update( m_name, colNames, colValues, where, &nullCols );
472 }
473
474 bool Table::fillProgramCols( Row& row, bool newRow ) const {
475 std::string val;
476
477 for ( unsigned i = 0; i < m_programCols.size(); i++ )
478 {
479 Column* col = m_programCols[i];
480 switch ( col->getContentsType() )
481 {
482 case Column::CONTENTSserviceName: val = "rdbModel"; break;
484#ifdef __GNUG__
485 val = std::string( "$(USER)" );
486#else
487 val = std::string( "$(USERNAME)" );
488#endif
489
490 int nsub = facilities::Util::expandEnvVar( &val );
491 if ( nsub != 1 ) { val = "no username"; }
492 break;
493 }
494
496 if ( !newRow ) continue; // otherwise, same as updateTime case
498 facilities::Timestamp curTime;
499 val = curTime.getString();
500 break;
501 }
502 default: return false; // unrecognized type
503 }
504 // look for this field in Row input. If there, overwrite value
505 FieldVal* f = row.find( col->getName() );
506 if ( f )
507 {
508 f->m_val = val;
509 f->m_null = false;
510 }
511 else
512 {
513 FieldVal g( col->getName(), val, false );
514 row.addField( g );
515 row.rowSort();
516 }
517 }
518 return true;
519 }
520
521 void Table::fillDefaults( Row& row ) const {
522 for ( unsigned i = 0; i < m_mayDefault.size(); i++ )
523 {
524 Column* hasDef = m_mayDefault[i];
525 FieldVal* f = row.find( hasDef->getName() );
526 if ( f ) continue;
527 // otherwise add it it
528 if ( ( hasDef->getDefault() ).size() > 0 )
529 {
530 FieldVal g( hasDef->getName(), hasDef->getDefault() );
531 row.addField( g );
532 }
533 else
534 { // null
535 FieldVal g( hasDef->getName(), "", true );
536 row.addField( g );
537 }
538 row.rowSort();
539 }
540 }
541
542 // Source in <set>
543 // should either be FIELDTYPElit or FIELDTYPEtoBe. In latter
544 // case, substitute from row argument.
545 bool Table::doInterUpdate( const std::vector<Set>& sets, Assertion* subsAssert,
546 Row& toBe ) const {
547 unsigned nSets = sets.size();
548 std::vector<FieldVal> fields;
549 fields.reserve( nSets );
550
551 for ( unsigned iSet = 0; iSet < sets.size(); iSet++ )
552 {
553 std::string col = sets[iSet].getDestColName();
554 std::string src;
555 // updateCols.push_back(sets[iSet].getDestColName());
556 FIELDTYPE srcType = sets[iSet].getSrcType();
557 if ( ( srcType == FIELDTYPElit ) || ( srcType == FIELDTYPElitDef ) )
558 {
559 src = sets[iSet].getSrcValue();
560 // May require special handling
561 if ( sets[iSet].hasInterp() )
562 {
563 Column* c = getColumnByName( col );
564 c->interpret( sets[iSet].getInterp(), src );
565 /* should know how to substitute, e.g. val="NOW" should
566 be transformed into a timestamp */
567 }
568 }
569 else
570 { // must be toBe
571 std::string toBeCol = sets[iSet].getSrcValue();
572 FieldVal* f = toBe.find( toBeCol );
573 if ( f == 0 )
574 {
575 delete subsAssert;
576 ( *m_out ) << "Table::InsertNew Row argument missing needed field" << toBeCol
577 << std::endl;
578 m_out->flush();
579 return false;
580 // throw RdbException
581 // ("Table::InsertNew Row argument missing needed field");
582 }
583 src = f->m_val;
584 // updateVals.push_back(f->m_val);
585 }
586 FieldVal g( col, src );
587 fields.push_back( g );
588 }
589 Row row( fields );
590
591 fillProgramCols( row, false );
592
593 std::vector<std::string> updateCols;
594 std::vector<std::string> updateVals;
595 std::vector<std::string> nullCols;
596
597 row.regroup( updateCols, updateVals, nullCols );
598
599 // Make specified changes (update)
600 m_connect->update( m_name, updateCols, updateVals, subsAssert );
601
602 delete subsAssert;
603 return true;
604 }
605
606 const std::string& Table::setPrimaryKeyCol() {
607 static const std::string empty( "" );
608 if ( m_primaryKeyCol.size() > 0 ) return m_primaryKeyCol;
609
610 for ( unsigned iCol = 0; iCol < m_cols.size(); iCol++ )
611 {
612 if ( m_cols[iCol]->isPrimaryKey() )
613 {
614 m_primaryKeyCol = m_cols[iCol]->getName();
615 return m_primaryKeyCol;
616 }
617 }
618 return empty;
619 }
620
621 bool Table::isSupersedable( std::string oldKeyStr ) const {
622 // Make a copy of supersedable condition
623 Row emptyRow;
624 Assertion::Operator* onlyIf =
625 new Assertion::Operator( ( m_sup->getOnlyIf() )->getOperator(), &emptyRow );
626 // Make operator for key == oldKey
627 Assertion::Operator* ser = new Assertion::Operator(
628 OPTYPEequal, m_primaryKeyCol, oldKeyStr, FIELDTYPEold, FIELDTYPElit );
629 std::vector<Assertion::Operator*> children;
630 children.push_back( onlyIf );
631 children.push_back( ser );
632 Assertion::Operator* whereOp = new Assertion::Operator( OPTYPEand, children );
633
634 std::vector<std::string> queryCols;
635 queryCols.push_back( m_primaryKeyCol );
636 Assertion* where = new Assertion( whereOp );
637 ResultHandle* results = m_connect->select( m_name, queryCols, queryCols, where );
638 delete where;
639
640 return ( results->getNRows() > 0 );
641 }
642
643} // namespace rdbModel
TFile f("ana_bhabha660a_dqa_mcPat_zy_old.root")
const Int_t n
****INTEGER imax DOUBLE PRECISION m_pi *DOUBLE PRECISION m_amfin DOUBLE PRECISION m_Chfin DOUBLE PRECISION m_Xenph DOUBLE PRECISION m_sinw2 DOUBLE PRECISION m_GFermi DOUBLE PRECISION m_MfinMin DOUBLE PRECISION m_ta2 INTEGER m_out INTEGER m_KeyFSR INTEGER m_KeyQCD *COMMON c_Semalib $ !copy of input $ !CMS energy $ !beam mass $ !final mass $ !beam charge $ !final charge $ !smallest final mass $ !Z mass $ !Z width $ !EW mixing angle $ !Gmu Fermi $ alphaQED at q
Definition KKsem.h:33
**********Class see also m_nmax DOUBLE PRECISION m_amel DOUBLE PRECISION m_x2 DOUBLE PRECISION m_alfinv DOUBLE PRECISION m_Xenph INTEGER m_KeyWtm INTEGER m_idyfs DOUBLE PRECISION m_zini DOUBLE PRECISION m_q2 DOUBLE PRECISION m_Wt_KF DOUBLE PRECISION m_WtCut INTEGER m_KFfin *COMMON c_KarLud $ !Input CMS energy[GeV] $ !CMS energy after beam spread beam strahlung[GeV] $ !Beam energy spread[GeV] $ !z boost due to beam spread $ !electron beam mass *ff pair spectrum $ !minimum v
Definition KarLud.h:35
std::string getString() const
Return string representation of time, not including nanoseconds;.
Definition Timestamp.cxx:87
static int expandEnvVar(std::string *toExpand, const std::string &openDel=std::string("$("), const std::string &closeDel=std::string(")"))
static const char * itoa(int val, std::string &outStr)
Function object used to sort columns by column name.
bool nullAllowed() const
Returns true if column may take on value NULL.
bool interpret(const std::string &interpType, std::string &val)
Definition Column.cxx:35
virtual std::ostream * getOut() const =0
virtual std::ostream * getErrOut() const =0
static void cleanFieldPtrs(std::vector< std::string * > &fields)
virtual bool getRowPtrs(std::vector< std::string * > &fields, unsigned int i=0, bool clear=true)=0
virtual unsigned int getNRows() const =0
Return number of rows in results.
FieldVal * find(std::string colname)
Definition Column.cxx:65
void rowSort()
Definition Column.cxx:57
void regroup(std::vector< std::string > &colNames, std::vector< std::string > &colVals, std::vector< std::string > &nullCols) const
Reorder information suitable for Connection::insert.
Definition Column.cxx:94
Visitor::VisitorState accept(Visitor *v)
Definition Table.cxx:117
int insertRow(Row &row, int *serial=0) const
Definition Table.cxx:271
Index * getIndexByName(const std::string &name) const
Definition Table.cxx:96
int insertLatest(Row &row, int *serial=0) const
Definition Table.cxx:173
int supersedeRow(Row &row, int oldKey, int *newKey=0) const
Definition Table.cxx:322
Assertion * getAssertionByName(const std::string &name) const
Definition Table.cxx:106
int updateRows(Row &row, Assertion *where) const
Definition Table.cxx:457
void sortColumns()
Definition Table.cxx:147
Column * getColumnByName(const std::string &name) const
Definition Table.cxx:67
void setConnection(Connection *connect)
Definition Table.cxx:60