/* ---- This file is part of SECONDO. Copyright (C) 2004-2009, University in Hagen, Faculty of Mathematics and Computer Science, Database Systems for New Applications. SECONDO is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. SECONDO is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with SECONDO; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ---- //[&] [\&] */ #include "ListUtils.h" #include "NestedList.h" #include "SecondoSystem.h" #include "Symbols.h" // Kind::*, Symbol::* #include "StandardTypes.h" // int, real, bool, string #include "Algebras/OldRelation-C++/OldRelationAlgebra.h" // rel, tuple #include "Algebras/Relation-C++/RelationAlgebra.h" // rel, trel, tuple #include "Algebras/OrderedRelation/OrderedRelationAlgebra.h" // orel #include "Algebras/TupleIdentifier/TupleIdentifier.h" // tid #include "Algebras/Rectangle/RectangleAlgebra.h" // rect, rect3, rect4, rect8 #include "Algebras/RTree/RTreeAlgebra.h" // rtree, rtree3, rtree4, rtee8 #include "Algebras/BTree/BTreeAlgebra.h" // btree #include "Algebras/BTree2/BTree2.h" // btree2 #include "Algebras/Hash/HashAlgebra.h" // hash #include #include #include extern NestedList* nl; using namespace std; namespace listutils{ /* Returns a list containing a symbol "ERROR"; */ ListExpr emptyErrorInfo(){ return nl->OneElemList(nl->SymbolAtom(Symbol::ERROR())); } /* Checks for a Spatial type. */ bool isSpatialType(ListExpr arg){ AlgebraManager *algMgr = SecondoSystem::GetAlgebraManager(); ListExpr errorInfo = emptyErrorInfo(); return algMgr->CheckKind(Kind::SPATIAL1D(), arg, errorInfo) || algMgr->CheckKind(Kind::SPATIAL2D(), arg, errorInfo) || algMgr->CheckKind(Kind::SPATIAL3D(), arg, errorInfo) || algMgr->CheckKind(Kind::SPATIAL4D(), arg, errorInfo) || algMgr->CheckKind(Kind::SPATIAL8D(), arg, errorInfo); } /* Checks for a rectangle type */ bool isRectangle(ListExpr arg){ return nl->IsEqual(arg, Rectangle<1>::BasicType()) || nl->IsEqual(arg, Rectangle<2>::BasicType()) || nl->IsEqual(arg, Rectangle<3>::BasicType()) || nl->IsEqual(arg, Rectangle<4>::BasicType()) || nl->IsEqual(arg, Rectangle<8>::BasicType()); } /* Creates a list "typeerror". */ ListExpr typeError(){ return nl->TypeError(); } /* Writes a message to the errorreporter and returns "typeerror". */ ListExpr typeError(string message){ ErrorReporter::ReportError(message); return nl->TypeError(); } /* Checks for a valid description of an rtree. */ bool isRTreeDescription(ListExpr rtree){ // (rtree tupledescription type bool) if(nl->ListLength(rtree)!=4){ return false; } ListExpr rtreeSymbol = nl->First(rtree); if(nl->AtomType(rtreeSymbol)!=SymbolType){ return false; } string rtreestr = nl->SymbolValue(rtreeSymbol); if( (rtreestr != RTree1TID::BasicType()) && (rtreestr != RTree2TID::BasicType()) && (rtreestr != RTree3TID::BasicType()) && (rtreestr != RTree4TID::BasicType()) && (rtreestr != RTree8TID::BasicType()) ){ return false; } if(!isTupleDescription(nl->Second(rtree))){ return false; } if(nl->AtomType(nl->Fourth(rtree))!= BoolType){ return false; } // check for valid type as third element omitted return true; } bool isRTreeDescription(ListExpr rtree, const string& basicType){ // (rtree tupledescription type bool) if(nl->ListLength(rtree)!=4){ return false; } ListExpr rtreeSymbol = nl->First(rtree); if(nl->AtomType(rtreeSymbol)!=SymbolType){ return false; } string rtreestr = nl->SymbolValue(rtreeSymbol); if( rtreestr != basicType) { return false; } if(!isTupleDescription(nl->Second(rtree))){ return false; } if(nl->AtomType(nl->Fourth(rtree))!= BoolType){ return false; } // check for valid type as third element omitted return true; } /* Checks for a BTreeDescription */ bool isBTreeDescription(ListExpr btree){ if((nl->ListLength(btree)<3) || (nl->ListLength(btree)>4)){ return false; } return nl->IsEqual(nl->First(btree),BTree::BasicType()) && isTupleDescription(nl->Second(btree)) && isDATA(nl->Third(btree)) && ((nl->ListLength(btree) == 3) || isKeyDescription(nl->Second(btree), nl->Fourth(btree))); } /* Checks wether the list given as argument is a type usuable as an key for a Berkeley DB index. */ bool isBDBIndexableType(ListExpr key){ ListExpr errorInfo = emptyErrorInfo(); AlgebraManager *algMgr = SecondoSystem::GetAlgebraManager(); bool indexable = algMgr->CheckKind(Kind::INDEXABLE(), key,errorInfo) || (nl->IsAtom(key) && nl->AtomType(key) == SymbolType && (nl->SymbolValue(key) == CcInt::BasicType() || nl->SymbolValue(key) == TupleIdentifier::BasicType() || nl->SymbolValue(key) == CcReal::BasicType() || nl->SymbolValue(key) == CcBool::BasicType() || nl->SymbolValue(key) == CcString::BasicType())); return indexable; } /* Checks for a BTree2Description */ bool isBTree2Description(ListExpr btree2){ if(nl->ListLength(btree2)!=4){ return false; } ListExpr uniq = nl->Fourth(btree2); ListExpr key = nl->Second(btree2); bool indexable = isBDBIndexableType(key); return (nl->IsEqual(nl->First(btree2),BTree2Algebra::BTree2::BasicType()) && indexable && nl->IsAtom(nl->Third(btree2)) && nl->AtomType(uniq) == SymbolType) && (nl->SymbolValue(uniq) == "multiple" || nl->SymbolValue(uniq) == "uniqueKey" || nl->SymbolValue(uniq) == "uniqueKeyMultiData"); } /* Checks for a valid hash table */ bool isHashDescription(ListExpr hash){ if(nl->ListLength(hash)!=3){ return false; } return isSymbol(nl->First(hash),Hash::BasicType()) && isTupleDescription(nl->Second(hash)) && isDATA(nl->Third(hash)); } /* Checks for valid description of a tuple. */ bool isTupleDescription(ListExpr tuple, const bool ismtuple /*=false*/){ if(nl->ListLength(tuple)!=2){ return false; } string tuplesym = ismtuple ?oldrelation::CcTuple::BasicType() :Tuple::BasicType(); if(!isSymbol(nl->First(tuple),tuplesym)){ return false; } return isAttrList(nl->Second(tuple)); } /* Checks for a valid atribute list */ bool isAttrList(ListExpr attrList){ ListExpr rest = attrList; ListExpr current; ListExpr errorInfo = emptyErrorInfo(); if(nl->AtomType(attrList)!=NoAtom){ return false; } if(nl->IsEmpty(attrList)){ return false; } set attrnames; while(!nl->IsEmpty(rest)) { current = nl->First(rest); rest = nl->Rest(rest); if(nl->ListLength(current)!=2){ return false; } ListExpr attrName = nl->First(current); ListExpr attrType = nl->Second(current); if(nl->AtomType(attrName)!=SymbolType){ return false; } string name = nl->SymbolValue(attrName); if(attrnames.find(name)!=attrnames.end()){ return false; } attrnames.insert(name); if(!am->CheckKind(Kind::DATA(), attrType, errorInfo)){ return false; } } return true; } /* Checks an attribute list for naming conventions */ bool checkAttrListForNamingConventions(ListExpr attrList){ // assert(isAttrList(attrList)); while(!nl->IsEmpty(attrList)){ if(!checkAttrForNamingConventions(nl->First(nl->First(attrList)))){ return false; } attrList = nl->Rest(attrList); } return true; } /* Checks an attribute name for naming conventions. */ bool checkAttrForNamingConventions(const ListExpr attr){ // assert(isSymbol(attr)) string name = nl->SymbolValue(attr); if(name.length()<1){ return false; } char f = name[0]; if(f<'A' || f>'Z'){ return false; } else { return true; } } bool isValidAttributeName(const ListExpr attr, string& error){ if(!isSymbol(attr)){ error = "attribute name is not a symbol"; return false; } string attrstr = nl->SymbolValue(attr); if(!SecondoSystem::GetCatalog()->IsValidIdentifier(attrstr, error)){ error = "attribute name "+ error + "."; return false; } if(!checkAttrForNamingConventions(attr)){ error = attrstr + " does not fit Secondo's names conventions"; return false; } return true; } /* Checks for disjoint attribute lists. Precondition isAttrList(l1) [&] isAttrList(l2) */ bool disjointAttrNames(ListExpr l1, ListExpr l2){ assert(isAttrList(l1)); assert(isAttrList(l2)); set names; ListExpr rest = l1; while(!nl->IsEmpty(rest)){ names.insert(nl->SymbolValue(nl->First(nl->First(rest)))); rest = nl->Rest(rest); } rest = l2; while(!nl->IsEmpty(rest)){ string name = nl->SymbolValue(nl->First(nl->First(rest))); if(names.find(name)!=names.end()){ return false; } rest = nl->Rest(rest); } return true; } /* Checks whether the list corresponds to a given symbol. */ bool isSymbol(const ListExpr list, const string& v){ if(nl->AtomType(list)!=SymbolType){ return false; } return nl->SymbolValue(list) == v; } bool isSymbol(const ListExpr list){ return nl->IsAtom(list) && (nl->AtomType(list)==SymbolType); } bool isASymbolIn(const ListExpr list, const set& s){ if(!isSymbol(list)){ return false; } string v = nl->SymbolValue(list); return s.find(v)!=s.end(); } /* Concatenates l1 and l2. */ ListExpr concat(ListExpr l1, ListExpr l2){ assert(nl->AtomType(l1) == NoAtom); assert(nl->AtomType(l2) == NoAtom); if(nl->IsEmpty(l1)){ return l2; } ListExpr res = nl->OneElemList(nl->First(l1)); l1 = nl->Rest(l1); ListExpr last = res; while(!nl->IsEmpty(l1)){ last = nl->Append(last, nl->First(l1)); l1 = nl->Rest(l1); } while(!nl->IsEmpty(l2)){ last = nl->Append(last, nl->First(l2)); l2 = nl->Rest(l2); } return res; } /* Returns the keytype fo an rtree description. */ ListExpr getRTreeType(ListExpr rtree){ assert(isRTreeDescription(rtree)); return nl->Third(rtree); } /* Returns the dimension of an rtree. */ int getRTreeDim(ListExpr rtree){ assert(isRTreeDescription(rtree)); string t = nl->SymbolValue(nl->First(rtree)); if(t==RTree1TID::BasicType()) return 1; if(t==RTree2TID::BasicType()) return 2; if(t==RTree3TID::BasicType()) return 3; if(t==RTree4TID::BasicType()) return 4; if(t==RTree8TID::BasicType()) return 8; assert(false); return -1; } /* Checks for a valid relation description. */ bool isRelDescription(ListExpr rel, const bool trel /*=false*/){ string relsymb = trel?TempRelation::BasicType():Relation::BasicType(); return isRelDescription2(rel, relsymb); } bool isRelDescription2(ListExpr rel, const string& relsymb){ if(nl->ListLength(rel)!=2){ return false; } if(!isSymbol(nl->First(rel),relsymb)){ return false; } bool mtuple = relsymb==oldrelation::CcRel::BasicType(); return isTupleDescription(nl->Second(rel),mtuple); } bool isOrelDescription(ListExpr orel) { if(nl->ListLength(orel)!=3) { return false; } return isSymbol(nl->First(orel),OrderedRelation::BasicType()) && isTupleDescription(nl->Second(orel),false) && isKeyDescription(nl->Second(orel), nl->Third(orel)); } bool isKeyDescription(ListExpr tupleList, ListExpr keyList) { ListExpr attrType; int attrIndex; if(nl->IsAtom(keyList)) { if(nl->AtomType(keyList)!=SymbolType) return false; attrIndex = findAttribute(nl->Second(tupleList), nl->SymbolValue(keyList), attrType); return attrIndex > 0 && isBDBIndexableType(attrType); } while(!nl->IsEmpty(keyList)) { ListExpr elem = nl->First(keyList); if(nl->AtomType(elem)!=SymbolType) { return false; } keyList = nl->Rest(keyList); ListExpr attrType; int attrIndex = findAttribute(nl->Second(tupleList), nl->SymbolValue(elem), attrType); if (attrIndex == 0 || !isBDBIndexableType(attrType)) { return false; } } return true; } /* Checks for a tuple stream */ bool isTupleStream(ListExpr s){ if(nl->ListLength(s)!=2){ return false; } if(!nl->IsEqual(nl->First(s),Symbol::STREAM())){ return false; } return isTupleDescription(nl->Second(s)); } /* Checks for Kind DATA */ bool isDATA(ListExpr type){ AlgebraManager *algMgr = SecondoSystem::GetAlgebraManager(); ListExpr errorInfo = emptyErrorInfo(); return algMgr->CheckKind(Kind::DATA(), type, errorInfo); } /* CHecks whether this list corresponds to a type in given kind */ bool isKind(ListExpr type, const string& kind){ AlgebraManager *algMgr = SecondoSystem::GetAlgebraManager(); ListExpr errorInfo = emptyErrorInfo(); return algMgr->CheckKind(kind, type, errorInfo); } /* Checks for a numeric type */ bool isNumeric(ListExpr num){ return nl->AtomType(num) == IntType || nl->AtomType(num) == RealType; } double getNumValue(ListExpr n){ if(nl->AtomType(n)==IntType){ return nl->IntValue(n); } if(nl->AtomType(n)==RealType){ return nl->RealValue(n); } else { assert(false); } return 0.0; } bool isNumericType(ListExpr n){ if(nl->AtomType(n)!=SymbolType){ return false; } string v = nl->SymbolValue(n); return v==CcInt::BasicType() || v==CcReal::BasicType(); } /* Checks for a stream of kind DATA */ bool isDATAStream(ListExpr s){ if(nl->ListLength(s)!=2){ return false; } if(!nl->IsEqual(nl->First(s),Symbol::STREAM())){ return false; } AlgebraManager *algMgr = SecondoSystem::GetAlgebraManager(); ListExpr errorInfo = emptyErrorInfo(); return algMgr->CheckKind(Kind::DATA(), nl->Second(s), errorInfo); } /* Checks whether the list represents a stream. */ bool isStream(ListExpr s){ if(nl->ListLength(s)!=2){ return false; } if(!nl->IsEqual(nl->First(s),Symbol::STREAM())){ return false; } return true; } int findAttribute(ListExpr attrList, const string& name, ListExpr& type){ assert(isAttrList(attrList)); int j = 0; ListExpr rest = attrList; while(!nl->IsEmpty(rest)){ ListExpr current = nl->First(rest); j++; if(nl->IsEqual(nl->First(current),name)){ type = nl->Second(current); return j; } rest = nl->Rest(rest); } return 0; } int findType(ListExpr attrList, const ListExpr type, string& name, const int start/*=1*/){ assert(isAttrList(attrList)); ListExpr rest = attrList; int j = 0; while(!nl->IsEmpty(rest)){ ListExpr current = nl->First(rest); rest = nl->Rest(rest); j++; if(j>=start){ if(nl->Equal(nl->Second(current),type)){ name = nl->SymbolValue(nl->First(current)); return j; } } } return 0; } int removeAttributes(ListExpr list, const set& names, ListExpr& head, ListExpr& last){ assert(isAttrList(list)); bool firstCall = true; int count = 0; while(!nl->IsEmpty(list)){ ListExpr pair = nl->First(list); list = nl->Rest(list); string name = nl->SymbolValue(nl->First(pair)); if(names.find(name)==names.end()){ if(firstCall){ firstCall=false; head = nl->OneElemList(pair); last = head; } else { last = nl->Append(last, pair); } } else { count++; } } if(firstCall){ head = nl->TheEmptyList(); last = head; } return count; } bool replaceAttributes( ListExpr attrList, map& renameMap, ListExpr& resAttrList, string& errmsg){ bool firstCall = true; ListExpr last = nl->TheEmptyList(); map::iterator it; while(!nl->IsEmpty(attrList)){ ListExpr attr = nl->First(attrList); attrList = nl->Rest(attrList); string name = nl->SymbolValue(nl->First(attr)); it = renameMap.find(name); ListExpr newAttr; if(it==renameMap.end()){ newAttr = attr; } else { newAttr = nl->TwoElemList( nl->SymbolAtom(it->second), nl->Second(attr)); renameMap.erase(it); } if(firstCall){ resAttrList = nl->OneElemList(newAttr); last = resAttrList; firstCall = false; } else { last = nl->Append(last, newAttr); } } if(firstCall){ errmsg = "empty attribute list cannot be renamed"; resAttrList = nl->TheEmptyList(); return false; } if(!renameMap.empty()){ it = renameMap.begin(); errmsg = "attribute " + it->first + " not found in attrlist"; resAttrList = nl->TheEmptyList(); return false; } if(!isAttrList(resAttrList)){ errmsg = "renamed names are not unique"; resAttrList = nl->TheEmptyList(); return false; } return true; } bool isSymbolUndefined( const string& s ) { return (s == Symbol::UNDEFINED()) || (s == "undef") || (s == "UNDEF") || (s == "undefined") || (s == "UNDEFINED") || (s == "null") || (s == "NULL") ; } bool isSymbolUndefined( ListExpr le ){ if(isSymbol(le)){ string s = nl->SymbolValue(le); return isSymbolUndefined(s); } else { return false; } } ListExpr getUndefined(){ return nl->SymbolAtom("undefined"); } string getUndefinedString(){ return "undefined"; } ListExpr getPtrList(const void* ptr){ // ensure that two int atoms can pick up a pointer assert(sizeof(void*) <= 8); uint32_t v1 = 0; uint32_t v2 = 0; uint64_t v = (uint64_t) ptr; v1 = v; // lower bits v2 = (v >> 32); // higher bits ListExpr res = nl->TwoElemList(nl->IntAtom(v2), nl->IntAtom(v1)); return res; } ListExpr getInt64List(const int64_t value){ int64_t min = numeric_limits::min(); int64_t max = numeric_limits::max(); if((min<=value) && (value <= max)){ return nl->IntAtom(value); } // ensure that two int atoms can pick up a pointer uint32_t v1 = 0; uint32_t v2 = 0; uint64_t v = (uint64_t) value; v1 = v; // lower bits v2 = (v >> 32); // higher bits ListExpr res = nl->TwoElemList(nl->IntAtom(v2), nl->IntAtom(v1)); return res; } bool decodeInt64(const ListExpr value, int64_t& result){ if(nl->AtomType(value)==IntType){ result = nl->IntValue(value); return true; } if(!nl->HasLength(value,2)){ return false; } ListExpr hb = nl->First(value); ListExpr lb = nl->Second(value); if(nl->AtomType(hb)!=IntType || nl->AtomType(lb)!=IntType){ return false; } uint64_t v1 = nl->IntValue(hb); uint64_t v2 = nl->IntValue(lb); uint64_t r = (v1 << 32) | v2; result = r; // implicit cast to signed return true; } bool isPtrList(const ListExpr list){ return nl->HasLength(list,2) && nl->AtomType(nl->First(list)) == IntType && nl->AtomType(nl->Second(list)) == IntType; } void* getPtr( const ListExpr ptrList){ uint64_t v2 = (uint32_t) nl->IntValue(nl->First(ptrList)); uint64_t v1 = (uint32_t) nl->IntValue(nl->Second(ptrList)); uint64_t v = (v2 << 32) | v1; return (void*) v; } string stringValue(ListExpr src){ if(nl->AtomType(src)==StringType){ return nl->StringValue(src); } if(nl->AtomType(src)==TextType){ return nl->Text2String(src); } return ""; } ListExpr xElemList(int count, ...){ if(count <= 0){ return nl->TheEmptyList(); } va_list ap; va_start(ap,count); ListExpr first = nl->OneElemList(va_arg(ap,ListExpr)); ListExpr last = first; for(int i=1;iAppend(last, va_arg(ap,ListExpr)); } va_end(ap); return first; } ListExpr simpleMessage(const string& msg){ return getMessage("simple",msg); } ListExpr simpleMessage(const int value){ return getMessage("simple", value); } ListExpr getMessage( const string& messageType, const string& message){ ListExpr l = message.length()>=MAX_STRINGSIZE ? nl->TextAtom(message) : nl->StringAtom(message); return nl->TwoElemList( nl->SymbolAtom(messageType),l); } ListExpr getMessage( const string& messageType, const int value){ return nl->TwoElemList( nl->SymbolAtom(messageType), nl->IntAtom(value)); } bool containsSymbol(ListExpr list, const string& symbol){ if(nl->AtomType(list)==SymbolType){ return nl->SymbolValue(list)==symbol; } if(nl->AtomType(list) != NoAtom){ return false; } while(!nl->IsEmpty(list)){ ListExpr f = nl->First(list); list = nl->Rest(list); if(containsSymbol(f,symbol)){ return true; } } return false; } bool isMapX(int x, ListExpr map){ int a = x+2; // (map arg1 arg2 .. argx result) return nl->ListLength(map)==a && nl->AtomType(nl->First(map))==SymbolType && nl->SymbolValue(nl->First(map)) == "map"; } bool isAnyMap(ListExpr map){ return nl->HasMinLength(map,2) && isSymbol(nl->First(map), "map"); } ListExpr replaceSymbol(ListExpr list, const std::string& symb, ListExpr replacement, NestedList* nl){ int t = nl->AtomType(list); switch(t){ case IntType : case RealType : case BoolType : case StringType : case TextType : return list; case SymbolType : { std::string s = nl->SymbolValue(list); return s==symb? replacement: list; } case NoAtom : { if(nl->IsEmpty(list)) return list; ListExpr cp = nl->OneElemList(replaceSymbol(nl->First(list), symb, replacement, nl)); ListExpr last = cp; ListExpr rest = nl->Rest(list); while(!nl->IsEmpty(rest)){ last = nl->Append(last, replaceSymbol(nl->First(rest),symb, replacement, nl)); rest = nl->Rest(rest); } return cp; } default: assert(false); return nl->TheEmptyList(); } } bool checkUsesArgsInTypeMapping(ListExpr args){ if(nl->AtomType(args)!= NoAtom){ return false; } while(nl->IsEmpty(args)){ if(!nl->HasLength(nl->First(args),2)){ return false; } args = nl->Rest(args); } return true; } ListExpr replaceSymbols(ListExpr list, const map& replacements){ if(nl->IsEmpty(list)){ return nl->TheEmptyList(); } switch(nl->AtomType(list)){ case SymbolType: { string symb = nl->SymbolValue(list); map::const_iterator it = replacements.find(symb); if(it==replacements.end()){ return list; } else { return it->second; } } case NoAtom: { ListExpr first = nl->OneElemList( replaceSymbols(nl->First(list), replacements)); ListExpr last = first; list = nl->Rest(list); while(!nl->IsEmpty(list)){ last = nl->Append(last, replaceSymbols(nl->First(list),replacements)); list = nl->Rest(list); } return first; } default: return list; } } } // end of namespace listutils