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

SQLtoLDAPQuerier.cpp

00001                               /* SQLtoLDAPQuerier.cpp */
00002 
00003 /*
00004  *  Implementation of SQLtoLDAPQuerier.h
00005  */
00006 #include "SQLtoLDAPQuerier.h"
00007 
00008 using namespace std;
00009 using namespace LcgInfo;
00010 
00011 typedef vector<vector<string> >::iterator matrStrIt;
00012 typedef vector<string>::iterator vecStrIt;
00013 typedef string::size_type strPos;
00014 
00015 /*****************   EXTERN SYMBOLS FOR GENERIC CLASS  ****************/
00019 extern "C" {
00020    Querier* SQLtoLDAPQuerier_create(){
00021       return new SQLtoLDAPQuerier();
00022    }
00023 }
00024 
00028 extern "C" {
00029    void SQLtoLDAPQuerier_destroy(Querier *p){
00030       delete p;
00031    }
00032 }
00033 
00034 /******************  METHODS FOR CLASS SQLtoLDAPQuerier  ********************/
00035 
00036 SQLtoLDAPQuerier::SQLtoLDAPQuerier()
00037    :mConf(0),mTranslator(0),mLdap(0){
00038 }
00039 
00040 SQLtoLDAPQuerier::~SQLtoLDAPQuerier(){
00041    delete mConf;
00042    mConf=0;
00043 }
00044 
00045 void SQLtoLDAPQuerier::setConfig(LcgConfigBuffer::ConfigBuffer & pConf){
00046    mConf=&pConf;
00047    mLdap=new InfoFromLDAP();
00048    mLdap->setConfig(pConf);
00049    mMap=new LcgConfigBuffer::ConfigBuffer();
00050    //It may throw a ConfigBufferException if no attribute found, or 
00051    //a QueryTranslationException if the mapping file is not proper
00052    try{
00053       string mappingFile=mConf->get_attribute_value("SCHEMA_MAPPING_FILE");
00054       mMap->populate_from_config(mappingFile);
00055    }catch(LcgConfigBuffer::CBException& e){
00056        string msg="No valid mapping file. Aborting.";
00057        msg += "\nUnderlying CBException message: " + e.what() + " +line: ";
00058        msg += int2str(e.get_line()) + " +file: " + e.get_file();
00059        throw QueryTranslationException(msg,__FILE__,__LINE__);
00060     }
00061    mTranslator=new SQLtoLDAPQueryTranslator(*mMap);
00062 }
00063 
00064 vector<vector<string> > SQLtoLDAPQuerier::query(string const & pCanonical){
00065  vector<vector<string> > resultsBuffer;
00066  try{
00067    string input=pCanonical;
00068    vector<string> translation=mTranslator->translateQuery(input);
00069 
00070    vector<strPos> subqueries;   //index of rows which contain past subqueries results
00071    vector<strPos> priorQueries; //numbers of prior subqueries that have to be substituted
00072    vector<strPos> cols;  //column indeces where we are operating
00073 
00074    strPos pos; //where
00075    vector<strPos> posList; //size(i)-posList(i) = pos where the #n# have to be substituted
00076    bool nplicate=false; //for subqueries that that need n-plicate (all but first one)
00077    bool replace=false;  //for subqueries in which there was a #n# substitution
00078 
00079    // Main loop on the queries passed (last is the results list)
00080    for(vecStrIt orgQry=translation.begin(); orgQry!=(translation.end()-1); orgQry++){
00081       if(orgQry!=translation.begin()) nplicate=true;
00082       else nplicate=false;
00083       replace=false;
00084       priorQueries.clear();
00085       posList.clear();
00086       cols.clear();
00087 
00088 //debug
00089 //         cout << "Original: "+ *orgQry << endl;
00090 //         cout << "--------------------------" << endl;
00091 //end debug
00092 
00093       // First localize in this query the "#n#" marks of previous queries
00094       pos=(*orgQry).find('#',0);
00095       while (pos != string::npos){
00096          int count=0; 
00097          bool substitute=true;
00098          for(int i=pos-1; (*orgQry).at(i)=='\\'; i--, count++); //count escape chars
00099          if(count>0){
00100             (*orgQry).erase(pos-count/2,count/2); //delete half of the "\"
00101             pos-=count/2;                    // adjust index (elements were eliminated)
00102             if(count%2!=0) substitute=false; 
00103          }
00104          if(substitute){                             // the "#" was not escaped, substitute it 
00105             replace=true;
00106             nplicate=true;
00107             strPos queryNumber=str2int(string(1,(*orgQry).at(pos+1)));
00108             (*orgQry).erase(pos,3);   //remove 1st and 2nd "#" and the query number
00109             if(subqueries.size()<=queryNumber){
00110                   string msg="Trying to substitute a query whose results are not present";
00111                   msg+="\nQuery number: " + int2str(queryNumber);
00112                   throw QueryTranslationException(msg,__FILE__,__LINE__);
00113             }
00114             priorQueries.push_back(queryNumber);
00115             posList.push_back(pos);
00116          }
00117          else (*orgQry).erase(pos-1,1);   //the "#" was escaped, just delete 1 more "\"
00118 
00119          pos = (*orgQry).find("#", pos+1);   // go for next one 
00120       }//end of while(localize #n#)
00121 
00122       //now, make the real substitutions and ldap calls
00123       vector<string> theQueries;
00124       vector<string> auxQueries;
00125       string toQuery;
00126       strPos maxsub;
00127 
00128       if(replace){
00129          //Recalculate the list of #n# positions, so that it counts from the end 
00130          for(vector<strPos>::iterator i=posList.begin(); i!=posList.end(); i++){
00131             (*i) = (*orgQry).size()-(*i);
00132          }      
00133          //put the biggest subquery (and posList) number last
00134          if(priorQueries.size()>0) maxsub=priorQueries.back();
00135          for(strPos priorIndx=0; priorIndx<priorQueries.size(); priorIndx++){
00136             strPos auxPrev=priorQueries.at(priorIndx);
00137             if(auxPrev>maxsub) {
00138                maxsub=auxPrev;
00139                priorQueries.erase(priorQueries.begin()+priorIndx); 
00140                priorQueries.push_back(maxsub);
00141                posList.push_back(posList.at(priorIndx));
00142                posList.erase(posList.begin()+priorIndx);
00143             }
00144          }
00145          //list of significant previous values
00146          vector<string> prior=resultsBuffer[subqueries[priorQueries.back()]];
00147       
00148          //loop on each diff column of values of prior queries (taking last one as reference)
00149          for(strPos colNum=0; colNum<prior.size() ; colNum++){ 
00150             if(colNum>0) {if(prior.at(colNum)==prior.at(colNum-1)) continue;}
00151             toQuery=*orgQry;
00152             //loop on all prior queries
00153             for(strPos priorIndx=0; priorIndx<priorQueries.size(); priorIndx++){  
00154                prior=resultsBuffer[subqueries[priorQueries[priorIndx]]];
00155                toQuery.insert(toQuery.size()-posList[priorIndx], prior[colNum]);  //substitute
00156             }//end of for(prior queries)
00157             cols.push_back(colNum);
00158             theQueries.push_back(toQuery); //store
00159          }//end of for(colNum)
00160       }//end of if(replace)
00161       else{  
00162          theQueries.push_back(*orgQry);  //no replace => just add the query to the list as it is 
00163       }
00164      
00165       //call ldap with col and query number of the last of the subqueries used
00166       strPos qryIndx=0;
00167       strPos offset=0;//takes into account that if several values are got, the column number increases
00168       for(vecStrIt currQry=theQueries.begin(); currQry!=theQueries.end(); currQry++, qryIndx++){
00169          string filter;   
00170          vector<string> attribs;
00171          vector<vector<string> > partialResults;
00172          strPos differentValues=1; //how many different values we have retrieved in last ldap query
00173 
00174          // Separate filter and attributes
00175          pos=(*currQry).find_last_of(')',(*currQry).size()-1); //where filter ends
00176          filter=(*currQry).substr(0,pos+1);  //substring with the filter
00177          tokenizeStr((*currQry).substr(pos+1),attribs);  //tokenize substring with the attributes
00178       
00179          // Perform the LDAP search and store the results
00180 //debug
00181 //cout << "Filter: " << filter << endl;
00182 //cout << "Attribs: ";
00183 //for (string::size_type i=0; i < attribs.size(); i++){
00184 //   cout << attribs.at(i);
00185 //}
00186 //cout << endl;
00187 //cout << "Asking: "+ *currQry << endl;
00188 //end debug
00189          partialResults.clear();
00190          try{
00191             partialResults=mLdap->query(filter,attribs);//can return several values, for several attr
00192          }catch(LcgConfigBuffer::CBException e){
00193              string msg="Error while querying the ldap interface. Aborting.";
00194              msg += "\nUnderlying CBException message: " + e.what() + " +line: ";
00195              msg += int2str(e.get_line()) + " +file: " + e.get_file();
00196              throw LcgInfoException(msg,__FILE__,__LINE__);
00197           }
00198          differentValues=partialResults[0].size();
00199 
00200          //This is not nice, but if keys were asked, we have to remove the leading "xxx=" part
00201          string::size_type which=0;
00202          for(vecStrIt attr=attribs.begin(); attr!=attribs.end(); attr++, which++){
00203             if(((*attr)=="GlueForeignKey")||(*attr)=="GlueChunkKey"){
00204                for(vecStrIt value=partialResults[which].begin();
00205                             value!=partialResults[which].end(); value++){
00206                   string::size_type auxPos=(*value).find_last_of('=',(*value).size()-1);
00207                   if(auxPos!=string::npos)  (*value)=(*value).substr(auxPos+1);
00208                }
00209             }
00210          }
00211          
00212 //debug
00213 //cout << "Getting: ";
00214 // for(matrStrIt r=partialResults.begin(); r!=partialResults.end(); r++){
00215 //   cout << "\n              ";
00216 //   for(vecStrIt k=(*r).begin(); k!=(*r).end(); k++)
00217 //      cout << *k << " ";
00218 //}
00219 //cout << "\n\n";
00220 //end of debug
00221 
00222          //n-plicate the resultsBuffer
00223          if(nplicate){
00224             strPos limit, ini;
00225             vector<string> prior;
00226             if(replace){
00227                ini=cols.at(qryIndx)+offset;
00228                limit=ini+1;
00229             }           
00230             else{
00231                limit=differentValues;
00232                ini=0;
00233             }
00234             //loop on the different values of the reference column
00235             for(strPos i=ini; i<limit; i++){ 
00236                strPos baseCol;
00237                if(replace){
00238                   baseCol=i;
00239                   prior=resultsBuffer[subqueries.at(maxsub)];
00240                }
00241                else{
00242                   prior=resultsBuffer[subqueries.back()];
00243                   baseCol=differentValues * i;
00244                }
00245                //loop on the different values of the reference column
00246                for(strPos colNum=baseCol; colNum<prior.size() && prior.at(colNum)==prior.at(baseCol); colNum++){
00247                   //loop on the different rows of the buffer
00248                   for(matrStrIt bufRow=resultsBuffer.begin();bufRow!=resultsBuffer.end();bufRow++){
00249                      if((*bufRow).size()>colNum){
00250                         //repeat each column as many times as diff values were got on last ldap call
00251                         for(strPos j=0; j<differentValues-1; j++){
00252                            (*bufRow).insert(((*bufRow).begin())+colNum, (*bufRow).at(colNum));
00253                         }
00254                      }
00255                   }
00256                }
00257 
00258             }//end of for(baseCol)
00259          }//end if(nplicate)
00260 
00261          //Add the new results to the buffer
00262          if(replace && (cols.at(qryIndx)!=0)){
00263             for(matrStrIt toStore=partialResults.begin(); toStore!=partialResults.end(); toStore++){
00264                resultsBuffer.back().insert(resultsBuffer.back().end(), (*toStore).begin(), (*toStore).end());
00265             }            
00266          }
00267          else if((!replace) && nplicate){ 
00268             for(matrStrIt toStore=partialResults.begin(); toStore!=partialResults.end(); toStore++){
00269                resultsBuffer.push_back(*toStore);
00270             }            
00271             for(strPos i=0; i<differentValues-1; i++){
00272                for(matrStrIt toStore=partialResults.begin(); toStore!=partialResults.end(); toStore++){
00273                   resultsBuffer.back().insert(resultsBuffer.back().end(),(*toStore).begin(), (*toStore).end());
00274                }
00275             }
00276          }
00277          else{ //for !replace && !nplicate and for replace when cols..==0
00278             for(matrStrIt toStore=partialResults.begin(); toStore!=partialResults.end(); toStore++){
00279                resultsBuffer.push_back(*toStore);
00280             }
00281          }
00282 
00283          //Add the position of relevant prior subquery to the index vector
00284          if ((!replace) || (cols.at(qryIndx)==0))
00285             subqueries.push_back(resultsBuffer.size()-partialResults.size());
00286 
00287          //Calculate the offset for next iteration
00288          offset+=differentValues-1;
00289       }//end of for(currQry)
00290                
00291    }//end of queries loop, for(translation)
00292 
00293 
00294    //Finally, select which rows of the matrix have to be returned
00295    vector<vector<string> > finalResults;
00296    vector<string> listOfResults;
00297    tokenizeStr(translation.back(), listOfResults, ",");
00298    for(vecStrIt i=listOfResults.begin(); i!=listOfResults.end(); i++){
00299       vector<string> numbers;
00300       tokenizeStr(*i, numbers, "-");
00301       strPos theLine=str2int(numbers[0]);
00302       string::size_type aux;
00303       if(numbers[1]=="1"){         
00304          if((aux=subqueries.at(theLine))!=string::npos){
00305             subqueries.at(theLine)=string::npos;
00306             strPos limit;
00307             if(subqueries.size()>theLine+1) limit=subqueries.at(theLine+1);
00308             else limit=resultsBuffer.size();
00309             for(string::size_type j=aux+1; j<limit; j++){
00310                finalResults.push_back(resultsBuffer.at(j));
00311             }
00312          }
00313       }
00314       else{
00315          aux=subqueries.at(theLine);
00316          finalResults.push_back(resultsBuffer.at(aux));
00317       }
00318       
00319    }
00320 
00321 
00322 //debug
00323 //   cout << "Final results: ";
00324 //   for(matrStrIt i=finalResults.begin(); i!=finalResults.end(); i++){
00325 //      cout << "\n              ";
00326 //      for(vecStrIt j=(*i).begin(); j!=(*i).end(); j++)
00327 //         cout << *j << " ";
00328 //   }
00329 //   cout << endl;
00330 //   cout << " ##############################################          ";
00331 //   cout << "\n******************************************************************************\n\n";
00332 //end of debug
00333 
00334    return finalResults;
00335 
00336  }catch(QueryTranslationException &e){
00337     cerr << e.what() << " +line: " << e.get_line() << " +file: " << e.get_file() << endl;;
00338     return resultsBuffer;
00339   }
00340 
00341 }//end of query()

Generated on Tue Oct 5 14:42:45 2004 for LCG Information System Interface by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002