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

PredicateTree.cpp

00001                               /* PredicateTree.cpp */
00002 
00003 /*
00004  *  Implementation of PredicateTree.h
00005  */
00006 #include "PredicateTree.h"
00007 
00008 using namespace LcgInfo;
00009 using namespace std;
00010 
00011 
00012 /**************************  METHODS FOR CLASS PredicateTree  ***************************/
00013 
00014 string const PredicateTree::CHARS_TO_ESCAPE_IN_LITERALS = "\t ><=!()";
00015 
00016 /***** Public functions *****/
00017 
00018 PredicateTree::PredicateTree() {
00019    mType=LEAF; mValue="EMPTY"; mDepth=0; mLeft=0; mRight=0;
00020 }
00021 
00022 PredicateTree::~PredicateTree(){
00023    if(left()!=0){
00024       delete left();
00025       setLeft(0);
00026    }
00027    if(right()!=0){
00028       delete right();
00029       setRight(0);
00030    }
00031 }
00032 
00033 bool const PredicateTree::operator==(PredicateTree const & other){
00034    bool leftPart=false, rightPart=false;
00035 
00036    //check this node's value
00037    if ((value()!=other.value()) || (type()!=other.type())) return false;
00038    
00039    //check the left child
00040    if(other.left()!=NULL){
00041       if (left()==NULL) return false;
00042       else leftPart=(*left() == *(other.left()));
00043    }      
00044    if(other.left()==NULL){
00045       if (left()!=NULL) return false;
00046       else leftPart=true;
00047    }
00048    
00049    //check the right child
00050    if(other.right()!=NULL){
00051       if (right()==NULL) return false;
00052       else rightPart=(*right() == *(other.right()));
00053    }      
00054    if(other.right()==NULL){
00055       if (right()!=NULL) return false;
00056       else rightPart=true;
00057    }
00058    
00059    return (leftPart && rightPart);
00060 }
00061 
00062 void PredicateTree::clear(){
00063    if(left()!=0){
00064       delete left();
00065       setLeft(0);
00066    }
00067    if(right()!=0){
00068       delete right();
00069       setRight(0);
00070    }
00071    setValue("");
00072    setDepth(0);
00073 }
00074 
00075 bool PredicateTree::empty(){
00076    if(left()!=0) return false;
00077    if(right()!=0) return false;
00078    if(value()!="") return false;
00079    if(depth()!=0) return false;
00080    return true;
00081 }
00082 
00083 void PredicateTree::translate(TableRowTranslator * pTRowT, vector<string> * pOrgTables,
00084                               set<string> * pNewTables){
00085 
00086    vector<string> predicatesToAdd; //this is needed because we must examine both children of a
00087                                 //comparison node before applying the predicates
00088 
00089    if(type()==BOOLEAN){  //for boolean nodes, just translate the children
00090       if(left()!=0) left()->translate(pTRowT, pOrgTables, pNewTables);
00091       if(right()!=0) right()->translate(pTRowT, pOrgTables, pNewTables);
00092       //but, check possible resulting identities!!
00093       if((left()!=0) && (left()->isIdentity())){
00094          if(value()=="OR"){
00095             delete right();
00096             setRight(0);
00097          }
00098          delete left();
00099          setLeft(0);
00100       }
00101       if((right()!=0) && (right()->isIdentity())){
00102          if(value()=="OR"){
00103             delete left();
00104             setLeft(0);
00105          }
00106          delete right();
00107          setRight(0);
00108       }
00109    }
00110 
00111    if(type()==LEAF){  //for leaf nodes, translate their names
00112       string translated;
00113       if((isNumber(value()))||isLiteral(value())) return;  //just leave it as it is
00114       else{  //it is a row name
00115          if(value().find('.')==string::npos) 
00116             //if it does not contain a table name, try with one of the provided in the from list
00117             for(vector<string>::iterator j=pOrgTables->begin(); j!=pOrgTables->end(); j++) 
00118                try{
00119                   translated=pTRowT->mapTableRow((*j)+'.'+value());
00120                }catch(LcgConfigBuffer::CBException & e){
00121                    if (e.what()=="+CB EXCEPTION: Attribute does not exist")
00122                       {} //it's not an attribute of that table, just go on
00123                    else{
00124                       string msg="The attribute matching is not working properly.";
00125                       msg+= "\nUnderlying LcgConfigBuffer::CBException message: " + e.what() + " +line: ";
00126                       msg+= int2str(e.get_line()) + " +file: " + e.get_file();
00127                       throw QueryTranslationException(msg,__FILE__,__LINE__);
00128                    }
00129                 }
00130          else //it contains the table and all
00131             try{
00132                 translated=pTRowT->mapTableRow(value());
00133             }catch(LcgConfigBuffer::CBException& e){
00134                 if (e.what()=="+CB EXCEPTION: Attribute does not exist")
00135                    {} //it's not an attribute of that table, just go on
00136                 else{
00137                    string msg="The attribute matching is not working properly.";
00138                    msg+= "\nUnderlying LcgConfigBuffer::CBException message: " + e.what() + " +line: ";
00139                    msg+= int2str(e.get_line()) + " +file: " + e.get_file();
00140                    throw QueryTranslationException(msg,__FILE__,__LINE__);
00141                 }
00142              }        
00143          pNewTables->insert(extractTable(translated)); // update new table list
00144          if(!translated.empty()) setValue(translated); //change value, unless there was no mapping
00145       }         
00146    }
00147 
00148    if(type()==COMPARISON){ //comparison node, translate each child and apply the struct changes
00149       if(left()!=NULL) left()->translate(pTRowT, pOrgTables, pNewTables); //translate left child
00150       if(pTRowT->thereIsStructChange()){    //and apply the predicates
00151          for(vector<string>::iterator i=pTRowT->getPredicatesBegin();
00152             i!=pTRowT->getPredicatesEnd(); i++){
00153                if((*i).at(0)=='+') predicatesToAdd.push_back((*i).substr(1));
00154                else{
00155                   string msg="Parsing error. Currently, a predicate rule must start with \"+\"";
00156                   msg+="\nPredicate: "+ (*i);
00157                   throw QueryTranslationException(msg,__FILE__,__LINE__);
00158                }
00159          }
00160          
00161       }
00162       if(right()!=NULL) right()->translate(pTRowT, pOrgTables, pNewTables);//translate right child
00163       if(pTRowT->thereIsStructChange())    //and apply the predicates
00164          for(vector<string>::iterator i=pTRowT->getPredicatesBegin();
00165             i!=pTRowT->getPredicatesEnd(); i++){
00166                if((*i).at(0)=='+') predicatesToAdd.push_back((*i).substr(1));
00167                else{
00168                   string msg="Parsing error. Currently, a predicate rule must start with \"+\"";
00169                   msg+="\nPredicate: "+ (*i);
00170                   throw QueryTranslationException(msg,__FILE__,__LINE__);
00171                }
00172          }
00173       for(vector<string>::iterator i=predicatesToAdd.begin();i!=predicatesToAdd.end(); i++){
00174          this->addAndPredicate(*i, *pNewTables);
00175       }
00176    }
00177 }
00178 
00179 void PredicateTree::print(){
00180    cout << value();
00181    if(mLeft!=NULL){
00182       cout << "\t";
00183       mLeft->print();
00184    }
00185    if(mRight!=NULL){
00186       cout << endl;
00187       for(int i=0; i<=mDepth; i++)   cout << "\t";
00188       mRight->print();
00189    }
00190 }
00191 
00192 /***** Protected functions *****/
00193 
00194 void PredicateTree::setLeft(PredicateTree* pLeft){
00195    mLeft=pLeft;
00196    if(mLeft!=NULL) mLeft->incrementDepth(depth()+1); //correct the depth of the nodes below
00197 }
00198 void PredicateTree::setRight(PredicateTree* pRight){
00199    mRight=pRight;
00200    if(mRight!=NULL) mRight->incrementDepth(depth()+1); //correct the depth of the nodes below 
00201 }
00202 
00203 void PredicateTree::incrementDepth(int pAmount){
00204    setDepth(pAmount);
00205    if(left()!=NULL) left()->incrementDepth(pAmount+1);
00206    if(right()!=NULL) right()->incrementDepth(pAmount+1);
00207 }
00208 
00209 bool PredicateTree::relatesTables(){
00210    if(type()!=COMPARISON) return false;
00211    if(right()==0) return false;
00212    if((isNumber(right()->value())) || (isLiteral(right()->value()))) return false;
00213    else return true;
00214 }
00215 
00216 bool PredicateTree::isIdentity() const{
00217    if (type()==COMPARISON){   //check that we do not add an identity
00218       if(((left())!=NULL)&&((right())!=NULL))
00219          if((left()->value())==(right()->value())) return true;         
00220    }
00221    return false;
00222 }
00223 
00224 bool PredicateTree::isRedundant(PredicateTree const & pPred){
00225    //check that we do not add an identity
00226    if(pPred.isIdentity()) return true;
00227 
00228    if((type() == BOOLEAN) && (value() == "AND")) { //if root is an AND node check children branches
00229       if(left()!=NULL) if(left()->isRedundant(pPred)) return true;
00230       if(right()!=NULL) if(right()->isRedundant(pPred)) return true;
00231    }
00232    if((*this) == (pPred)) return true;  //adding what there is already is redundant
00233 
00234    return false; //if arrived here, it is that they are different
00235 }
00236 
00237 void PredicateTree::addAndPredicate(string const& pPred, set<string> & pNewTables){
00238    PredicateTree* newPred;
00239 
00240    //first, check that the new predicate is not redundant
00241    newPred=create();
00242    newPred->insertPredicate(pPred);
00243    if(this->isRedundant(*newPred)) return;
00244 
00245    //otherwise, just make the insertion
00246    PredicateTree* tempLeft;
00247    PredicateTree* tempRight;
00248    tempLeft=this->left();   // temporary pointer to what there is on the left branch of this node
00249    tempRight=this->right(); // temporary pointer to what there is on the right branch
00250    
00251    this->setLeft(NULL);   //remove the pointer from this node (root) to the branches
00252    this->setRight(NULL);
00253 
00254    this->setLeft(this->clone());  //replicate this node as its own left child
00255 
00256    this->left()->setLeft(tempLeft);  //copy the original left and right branches to the new node
00257    this->left()->setRight(tempRight);
00258 
00259    this->setType(BOOLEAN);  //now, change the type and contents of the root node
00260    this->setValue("AND");   //so that it becomes an AND node
00261 
00262    this->setRight(newPred);    //finally, add the new predicate's tree as root's right child
00263 
00264    // We also have to update new table list
00265    string aux=pPred;
00266    escapeLiterals(aux, this->getCHARS_TO_TOKENIZE_PREDICATES());
00267    vector<string> tokens; //let us get the table.row items
00268    tokenizeStr(aux, tokens, this->getCHARS_TO_TOKENIZE_PREDICATES());
00269    for(vector<string>::iterator k=tokens.begin(); k!=tokens.end(); k++){
00270       if((!isNumber(*k))&&(!isLiteral(*k))){
00271          pNewTables.insert(extractTable(*k));  //{+...} insert if not present
00272       }
00273    }
00274    unescapeLiterals(aux, this->getCHARS_TO_TOKENIZE_PREDICATES());
00275 }
00276 
00277 bool PredicateTree::isBooleanOp(string pStr){
00278    return nocaseCompare(pStr,"NOT") || nocaseCompare(pStr,"AND") || nocaseCompare(pStr,"OR");
00279 }
00280 
00281 string PredicateTree::getCHARS_TO_TOKENIZE_PREDICATES(){
00282    return "\t ><=!()";
00283 }

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