Main Page   Namespace List   Class Hierarchy   Compound List   File List   Namespace Members   Compound Members   File Members  

CdbMySQLConditionAtFolder.cc

Go to the documentation of this file.
00001 // File and Version Information:
00002 //      $Id: CdbMySQLConditionAtFolder.cc,v 1.9 2005/11/23 03:21:11 gapon Exp $
00003 
00004 /// The implementation of the CdbMySQLConditionAtFolder interface.
00005 /**
00006   * @see CdbMySQLConditionAtFolder
00007   */
00008 
00009 #include "BaBar/BaBar.hh"
00010 
00011 #include "CdbMySQL/CdbMySQLConditionAtFolder.hh"
00012 #include "CdbMySQL/CdbMySQLConnection.hh"
00013 #include "CdbMySQL/CdbMySQLSelectQuery.hh"
00014 #include "CdbMySQL/CdbMySQLQueryUtils.hh"
00015 
00016 #include "CdbSQL/CdbSQLOrigin.hh"
00017 #include "CdbSQL/CdbSQLView.hh"
00018 #include "CdbSQL/CdbSQLFolder.hh"
00019 
00020 #include "CdbBase/CdbConfigElement.hh"
00021 #include "CdbBase/CdbPathName.hh"
00022 #include "CdbBase/CdbTimeUtils.hh"
00023 
00024 #include "RdbMySQL/RdbMySQLResult.hh"
00025 
00026 #include <assert.h>
00027 
00028 #include <iostream>
00029 using std::cerr;
00030 using std::endl;
00031 
00032 #include <sstream>
00033 using std::ostringstream;
00034 
00035 CdbMySQLConditionAtFolder::CdbMySQLConditionAtFolder( const CdbCPtr<CdbMySQLConnection>& theConnectionPtr,
00036                                                       const CdbCPtr<CdbSQLFolder>&       theParentFolderPtr,
00037                                                       const CdbId&                       thePhysicalId,
00038                                                       const std::string&                 theName,
00039                                                       const BdbTime&                     theCreationTime,
00040                                                       const std::string&                 theDescription ) :
00041     CdbSQLConditionAtFolder( theParentFolderPtr,
00042                              thePhysicalId,
00043                              theName,
00044                              theCreationTime,
00045                              theDescription ),
00046    _myConnectionObjectPtr(theConnectionPtr)
00047 {
00048     assert( !theConnectionPtr.isNull( ));
00049 }
00050 
00051 CdbMySQLConditionAtFolder::CdbMySQLConditionAtFolder( const CdbMySQLConditionAtFolder& theOther ) : 
00052     CdbSQLConditionAtFolder( theOther ),
00053     _myConnectionObjectPtr(theOther._myConnectionObjectPtr)
00054 { }
00055 
00056 CdbMySQLConditionAtFolder::~CdbMySQLConditionAtFolder( )
00057 { }
00058 
00059 CdbStatus
00060 CdbMySQLConditionAtFolder::find_config_element( CdbConfigElement& theElement,
00061                                                 const BdbTime&    theValidityTime )
00062 {
00063     const char* errorStr = "CdbMySQLConditionAtFolder::find_config_element() -- ERROR.";
00064 
00065     CdbStatus result = CdbStatus::Error;
00066     do {
00067 
00068       // Formulate a query
00069 
00070         const unsigned short originId = parent( )->parentView( )->parent( )->id( );
00071         const unsigned short   viewId = parent( )->parentView( )->id( );
00072 
00073         std::string query;
00074         {
00075             ostringstream s;
00076             s << "SELECT "
00077               <<   "c.begin begin, c.end end, c.use_revision use_revision, c.partition_id partition_id, c.revision revision "
00078               << "FROM "
00079               <<   _myConnectionObjectPtr->database( ) << ".o" << originId << "_folders_conditions fc, "
00080               <<   _myConnectionObjectPtr->database( ) << ".o" << originId << "_conditions_configs c "
00081               << "WHERE "
00082               <<   "fc.view_id = " << viewId << " "
00083               << "AND "
00084               <<   "BINARY fc.path = '" << _myConnectionObjectPtr->translate_string_to_escaped( CdbPathName::separatorTerminated( parent( )->fullPathName( )))
00085               <<                           _myConnectionObjectPtr->translate_string_to_escaped( name( )) << "' "
00086               << "AND "
00087               <<   "fc.entry_type = 'C' "
00088               << "AND "
00089               <<   "fc.id = c.entry_id "
00090               << "AND "
00091               <<   "c.begin <= " << CdbTimeUtils::to_nsec( theValidityTime ) << " "
00092               << "AND "
00093               <<   CdbTimeUtils::to_nsec( theValidityTime ) << " < c.end;";
00094             query = s.str( );
00095         }
00096 
00097       // Execute the query
00098 
00099         CdbMySQLSelectQuery selectQuery( _myConnectionObjectPtr,
00100                                          query );
00101 
00102         std::vector<CdbConfigElement> listOfElements;
00103 
00104         if( !execute_query( selectQuery, listOfElements )) {
00105             cerr << errorStr << endl
00106                  << "    Failed to execute the query and/or translate its results." << endl
00107                  << "        QUERY : \"" << query.c_str( ) << "\"" << endl;
00108             break;
00109         }
00110         unsigned int numFound = listOfElements.size( );
00111         if( 1 != numFound) {
00112             if( 0 == numFound ) {
00113                 result = CdbStatus::NotFound;
00114                 break;
00115             }
00116             cerr << errorStr << endl
00117                  << "    The query executor returned unexpected number of rows." << endl
00118                  << "    The number of entries matching the query is " << numFound << "." << endl
00119                  << "        QUERY : \"" << query << "\"" << endl;
00120             break;
00121         }
00122 
00123       // Done
00124 
00125         theElement = listOfElements[0];
00126 
00127         result = CdbStatus::Success;
00128 
00129     } while( false );
00130 
00131     return result;
00132 }
00133 
00134 CdbStatus
00135 CdbMySQLConditionAtFolder::config_elements( std::vector<CdbConfigElement>& theList )
00136 {
00137     const char* errorStr = "CdbMySQLConditionAtFolder::config_elements() -- ERROR.";
00138 
00139     CdbStatus result = CdbStatus::Error;
00140     do {
00141 
00142       // Formulate the query
00143 
00144         const unsigned short originId = parent( )->parentView( )->parent( )->id( );
00145         const unsigned short   viewId = parent( )->parentView( )->id( );
00146 
00147         std::string query;
00148         {
00149             ostringstream s;
00150             s << "SELECT "
00151               <<   "c.begin begin,c.end end, c.use_revision use_revision, c.partition_id partition_id, c.revision revision "
00152               << "FROM "
00153               <<   _myConnectionObjectPtr->database( ) << ".o" << originId << "_folders_conditions fc, "
00154               <<   _myConnectionObjectPtr->database( ) << ".o" << originId << "_conditions_configs c "
00155               << "WHERE "
00156               <<   "fc.view_id = " << viewId << " "
00157               << "AND "
00158               <<   "BINARY fc.path = '" << _myConnectionObjectPtr->translate_string_to_escaped( CdbPathName::separatorTerminated( parent( )->fullPathName( )))
00159               <<                           _myConnectionObjectPtr->translate_string_to_escaped( name( )) << "' "
00160               << "AND "
00161               <<   "fc.entry_type = 'C' "
00162               << "AND "
00163               <<   "fc.id = c.entry_id "
00164               << "ORDER BY "
00165               <<   "c.begin;";
00166             query = s.str( );
00167         }
00168 
00169         CdbMySQLSelectQuery selectQuery( _myConnectionObjectPtr,
00170                                          query );
00171 
00172         if( !execute_query( selectQuery, theList )) {
00173             cerr << errorStr << "\n"
00174                  << "    Failed to execute the query and/or translate its results.\n"
00175                  << "        Query : \"" << query.c_str( ) << "\"" << endl;
00176             break;
00177         }
00178 
00179       // Done
00180 
00181         result = CdbStatus::Success;
00182 
00183     } while( false );
00184 
00185     return result;
00186 }
00187 
00188 CdbStatus
00189 CdbMySQLConditionAtFolder::set_config( std::vector<CdbConfigElement>& theList,
00190                                        const bool                     patchOnlyFlag )
00191 {
00192     const char* errorStr = "CdbMySQLConditionAtFolder::set_config() -- ERROR.";
00193     const char* context  = "CdbMySQLConditionAtFolder::set_config()";
00194 
00195   // Save the current configuration first
00196 
00197     std::vector<CdbConfigElement> savedConfigList;
00198     if( CdbStatus::Success != config_elements( savedConfigList )) {
00199         cerr << errorStr << "\n"
00200              << "    Failed to get the current configuration." << endl;
00201         return CdbStatus::Error;
00202     }
00203 
00204   // Tables we're going to deal with
00205 
00206     std::string foldersConditionsTableName;
00207     std::string conditionConfigsTableName;
00208     {
00209         ostringstream s;
00210         s << _myConnectionObjectPtr->database( ) << ".o" << parent( )->parentView( )->parent( )->id ( );
00211         const std::string baseTableName = s.str( );
00212 
00213         foldersConditionsTableName = baseTableName + "_folders_conditions";
00214         conditionConfigsTableName  = baseTableName + "_conditions_configs";
00215     }
00216 
00217   // Get the "entry id" for the current condition. That identifier serves as a primary key
00218   // in a table of "folders & conditions". We need to know it as a foreign key when manipulating
00219   // entries in a table of "condition configs".
00220 
00221     unsigned int entryId = 0;
00222     {
00223         ostringstream s;
00224         s << "SELECT id FROM " << foldersConditionsTableName
00225           << " WHERE view_id = " << parent( )->parentView( )->id( )
00226           << " AND BINARY path = '" << _myConnectionObjectPtr->translate_string_to_escaped( CdbPathName::separatorTerminated( parent( )->fullPathName( )))
00227           <<                           _myConnectionObjectPtr->translate_string_to_escaped( name( )) << "'";
00228         const std::string query = s.str( );
00229 
00230         CdbMySQLSelectQuery selectQuery( _myConnectionObjectPtr,
00231                                          query );
00232 
00233         if( !execute_query( selectQuery, entryId )) {
00234             cerr << errorStr << "\n"
00235                  << "    Failed to execute the query and/or translate its results.\n"
00236                  << "        Query : \"" << query.c_str( ) << "\"" << endl;
00237             return CdbStatus::Error;
00238         }
00239     }
00240 
00241   // Get rid of the current configuration in the database
00242 
00243     {
00244         ostringstream s;
00245         s << "DELETE FROM " << conditionConfigsTableName << " WHERE entry_id = " << entryId;
00246         const std::string query = s.str( );
00247 
00248         CdbCPtr<RdbMySQLResult> resultPtr;
00249         if( CdbStatus::Success != CdbMySQLQueryUtils::execute_query( resultPtr,
00250                                                                     _myConnectionObjectPtr,
00251                                                                     query,
00252                                                                     context )) return CdbStatus::Error;
00253     }
00254 
00255   // Merge the input configuration with the saved one taking into accound the "patchOnlyFlag".
00256   // At this step we'll produce a new configuration list
00257 
00258     std::vector<CdbConfigElement> newConfigList;
00259     {
00260         if( patchOnlyFlag ) {
00261 
00262             std::vector<CdbConfigElement>::const_iterator savedItr = savedConfigList.begin( );
00263             std::vector<CdbConfigElement>::const_iterator inputItr = theList.begin( );
00264 
00265             BdbTime prevEnd = BdbTime::minusInfinity;
00266 
00267             while( BdbTime::plusInfinity != prevEnd ) {
00268 
00269                 if( inputItr == theList.end( )) {
00270 
00271                   // When all input elements are exhausted then we simply copy the rest (if anything
00272                   // is still left) of the saved list into the output vector.
00273 
00274                     for( ; savedItr != savedConfigList.end( ); ++savedItr ) {
00275 
00276                         CdbConfigElement saved = *savedItr;
00277 
00278                       // Skip the element if it ended before the previously recorded end time
00279 
00280                         if( saved.end <= prevEnd ) continue;
00281 
00282                       // Truncate the begin time of the interval if it starts earlier than the end
00283                       // time of the previously stored new configuration
00284 
00285                         BdbTime adjustedBeginTime = saved.begin;
00286                         if( adjustedBeginTime < prevEnd ) adjustedBeginTime = prevEnd;
00287 
00288                         newConfigList.push_back( CdbConfigElement( saved.policy,
00289                                                                    adjustedBeginTime,
00290                                                                    saved.end ));
00291                         prevEnd = saved.end;
00292                     }
00293 
00294                   // Terminate the loop
00295 
00296                     prevEnd = BdbTime::plusInfinity;
00297 
00298                     break;
00299 
00300                 } else {
00301 
00302                     CdbConfigElement input = *(inputItr++);
00303 
00304                   // Check if there are saved elements in between the end time of the previously
00305                   // stored configuration and the begin time of the above found input one. If so
00306                   // then we need to store them as well.
00307 
00308                     if( input.begin > prevEnd ) {
00309 
00310                         for( ; savedItr != savedConfigList.end( ); ++savedItr ) {
00311 
00312                             CdbConfigElement saved = *savedItr;
00313 
00314                           // Skip the saved element if it ends before the end of the previously stored
00315                           // end time.
00316                           //
00317                           // NOTE: To tell the truth getting there is supposed to be an algorithm error.
00318                           //       So let's just check this and provoke a crash in case if the code gets
00319                           //       compiled in the DEBUG mode
00320 
00321                             if( saved.end <= prevEnd ) {
00322                                 assert( 0 );    // A bug in the current algorithm
00323                                 continue;
00324                             }
00325 
00326                           // Quit the loop of the saved element begins after the begin time
00327                           // of the currently processed input one
00328 
00329                             if( saved.begin > input.begin ) break;
00330 
00331                           // Adjust both the begin and the end times of the saved interval, so that
00332                           // it won't be beyond the limits between the end of the previously stored
00333                           // interval and the begin time of the current input one.
00334 
00335                             BdbTime adjustedBeginTime = saved.begin;
00336                             if( adjustedBeginTime < prevEnd ) adjustedBeginTime = prevEnd;
00337 
00338                             BdbTime adjustedEndTime = saved.end;
00339                             if( adjustedEndTime > input.begin ) adjustedEndTime = input.begin;
00340 
00341                             assert( adjustedBeginTime <= adjustedEndTime ); // A bug in the current algorithm
00342 
00343                           // Save the (truncated) element only if it doesn't have a zero length, which
00344                           // may happen if the saved interval is completelly hidden by the input one
00345 
00346                             if( adjustedBeginTime < adjustedEndTime )
00347                                 newConfigList.push_back( CdbConfigElement( saved.policy,
00348                                                                            adjustedBeginTime,
00349                                                                            adjustedEndTime ));
00350                         }
00351                     }
00352 
00353                   // Store the input element as well
00354 
00355                     newConfigList.push_back( input );
00356 
00357                     prevEnd = input.end;
00358                 }
00359             }
00360 
00361         } else {
00362             newConfigList = theList;
00363         }
00364     }
00365 
00366   // Load the new configuration into the database
00367 
00368     {
00369         const unsigned int num = newConfigList.size( );
00370         for( unsigned int i = 0; i < num; ++i ) {
00371             CdbConfigElement e = newConfigList[i];
00372             if( e.accessIsAllowed ) {
00373                 ostringstream s;
00374                 s << "INSERT INTO " << conditionConfigsTableName << " (entry_id,begin,end,use_revision,partition_id,revision ) VALUES ("
00375                   << entryId << ","
00376                   << CdbTimeUtils::to_nsec( e.begin ) << ","
00377                   << CdbTimeUtils::to_nsec( e.end ) << ",'"
00378                   << ( e.policy.useRevision( ) ? 'Y' : 'N' ) << "',"
00379                   << e.policy.partitionId( ) << ","
00380                   << CdbTimeUtils::to_nsec( e.policy.revisionId( )) << ")";
00381                 const std::string query = s.str( );
00382 
00383                 CdbCPtr<RdbMySQLResult> resultPtr;
00384                 if( CdbStatus::Success != CdbMySQLQueryUtils::execute_query( resultPtr,
00385                                                                             _myConnectionObjectPtr,
00386                                                                             query,
00387                                                                             context )) return CdbStatus::Error;
00388             }
00389         }
00390     }
00391     return CdbStatus::Success;
00392 }
00393 
00394 CdbMySQLConditionAtFolder::CloneType*
00395 CdbMySQLConditionAtFolder::clone( ) const
00396 {
00397     return new CdbMySQLConditionAtFolder( *this );
00398 }
00399 
00400 bool
00401 CdbMySQLConditionAtFolder::equals( const ComparedType& theOtherObject ) const
00402 {
00403     const char* warningStr = "CdbMySQLConditionAtFolder::equals() -- WARNING";
00404     cerr << warningStr << "\n"
00405          << "    This operation is not implemented." << endl;
00406     return false;
00407 }
00408 
00409 bool
00410 CdbMySQLConditionAtFolder::execute_query( CdbMySQLSelectQuery&           theQuery,
00411                                           std::vector<CdbConfigElement>& theList )
00412 {
00413     const char* errorStr = "CdbMySQLConditionAtFolder::execute_query(folder) -- ERROR";
00414 
00415     theList.clear( );
00416 
00417   // Process row-by-row and translate results
00418 
00419     while( true ) {
00420 
00421       // Move to the next row
00422 
00423         CdbStatus status = theQuery.next_row( );
00424         if( CdbStatus::Success != status ) {
00425             if( CdbStatus::NotFound == status ) break;
00426 
00427             cerr << errorStr << "\n"
00428                  << "    Failed to get result of the next row." << endl;
00429             return false;
00430         }
00431 
00432       // Now do the interpretation of values of fileds in the row.
00433       //
00434       // NOTE: We're assuming that results returned by the query are consistent
00435       //       with our expectations on how the table shoudl look alike.
00436 
00437         BdbTime        begin        = BdbTime::minusInfinity;
00438         BdbTime        end          = BdbTime::minusInfinity;
00439         std::string    use_revision = "";
00440         unsigned short partition_id = 0xFFFF;
00441         BdbTime        revision     = BdbTime::minusInfinity;
00442 
00443         theQuery.get( begin,        "begin"        );
00444         theQuery.get( end,          "end"          );
00445         theQuery.get( use_revision, "use_revision" );
00446         theQuery.get( partition_id, "partition_id" );
00447         theQuery.get( revision,     "revision"     );
00448 
00449       // Create the desired object
00450       //
00451       // NOTE: A clone of the current object will be the parent object of
00452       //       of the newely created one.
00453 
00454         theList.push_back( CdbConfigElement(( 'Y' == use_revision[0] ? CdbRevisionPolicy( revision, partition_id )
00455                                                                      : CdbRevisionPolicy( )),
00456                                              begin,
00457                                              end ));
00458     }
00459     return true;
00460 }
00461 
00462 bool
00463 CdbMySQLConditionAtFolder::execute_query( CdbMySQLSelectQuery& theQuery,
00464                                           unsigned int&        theId )
00465 {
00466     const char* errorStr = "CdbMySQLConditionAtFolder::execute_query(entry_id) -- ERROR";
00467 
00468   // Process the first row (if any) only. We don't care if there will be more rows.
00469   // However, we do care that the must be at least one row in a set. Otherwise the table's contents
00470   // would be inconsistent.
00471 
00472     CdbStatus status = theQuery.next_row( );
00473     if( CdbStatus::Success != status ) {
00474         if( CdbStatus::NotFound == status ) {
00475             cerr << errorStr << "\n"
00476                  << "    The contents of teh database has foumd not to be consistent.\n"
00477                  << "    There must be exactly one row in the set." << endl;
00478         } else {
00479             cerr << errorStr << "\n"
00480                  << "    Failed to get result of the next row." << endl;
00481         }
00482         return false;
00483     }
00484     theQuery.get( theId, "id" );
00485     return true;
00486 }
00487 
00488 /////////////////
00489 // End Of File //
00490 /////////////////

Generated on Mon Dec 5 18:22:07 2005 for CDB by doxygen1.3-rc3