/* ---- This file is part of SECONDO. Copyright (C) 2004, University in Hagen, Department of 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 ---- //paragraph [1] Title: [{\Large \bf \begin{center}] [\end{center}}] //paragraph [10] Footnote: [{\footnote{] [}}] //[->] [$\rightarrow$] //[TOC] [\tableofcontents] //[_] [\_] FileIndexAlgebra */ #include #include "Algebra.h" #include "NestedList.h" #include "QueryProcessor.h" #include "SecondoSystem.h" #include "Attribute.h" #include "Symbols.h" #include "Algebras/TupleIdentifier/TupleIdentifier.h" #include "StandardTypes.h" #include "Algebras/Spatial/SpatialAlgebra.h" #include "ListUtils.h" #include "Stream.h" #include "Algebras/Rectangle/RectangleAlgebra.h" #include "Algebras/FText/FTextAlgebra.h" #include "Algebras/TupleIdentifier/TupleIdentifier.h" #include "Algebras/MMRTree/MMRTreeAlgebra.h" #include "MMRTree.h" #include "RTreeNode.h" #include "RTree.h" #include "RTreeIterator.h" #include "Algebras/Spatial/SpatialAlgebra.h" #include #include "Cache/LruCache.h" #include "BPTree/BPTreeOperators.h" #include extern NestedList* nl; extern QueryProcessor* qp; extern AlgebraManager *am; using listutils::isTupleStream; using std::exception; using namespace std; namespace fialgebra { // detects dimension of a tree // stored in a file int checkDimension(const char* fileName){ ifstream stream(fileName, ifstream::binary | ifstream::ate); if ( !stream.good() ) { stream.close(); throw runtime_error( "File couldn't be opened: " + string(fileName) ); } else { size_t pageSize = WinUnix::getPageSize(), length = min(pageSize, stream.tellg()); stream.seekg(0, ios::beg); char* bytes = new char[length]; stream.read( bytes, length ); stream.close(); RTreeHeader* header = new RTreeHeader(bytes, length, pageSize, 1); size_t dimension = header->GetDimension(); delete header; return (int)dimension; } // else } /* supporting function: Checks the header * of an RTree. * */ template bool checkHeader(string& fileName, string& errMsg){ errMsg =""; /* open function also checks whether this is * a valid rtree which has been passed in the file*/ RTree* rt1 = RTree::Open(fileName.c_str(), 1); size_t rootId = 0; rootId = rt1->GetHeader()->GetRoot(); delete rt1; // Wenn die RootNode-ID 0 ist, ist der Baum leer if ( rootId == 0 ){ errMsg= "RTree is empty" ; return false; } return true; } /* There are no attributes in this algebra Operators implementation TypeMapping Functions operator ~fwindowintersects~ */ ListExpr fWindowIntersectTM(ListExpr args){ // args: ((text 'ix_rtree.bin') (rect (rect (1 1 1 1)))) //check number of arguments if (!nl->HasLength(args, 2)) return listutils::typeError("wrong number of aruments"); ListExpr fileArg = nl->First(args); //the list is coded as ( ) if(!nl->HasLength(fileArg, 2)){ return listutils::typeError("internal error"); } //first arguments must be of a type string or text if (!CcString::checkType(nl->First(fileArg)) && !FText::checkType(nl->First(fileArg))){ return listutils::typeError("file name as argument expected"); } ListExpr fn = nl->Second(fileArg); if(!((nl->AtomType(fn) == TextType) || (nl->AtomType(fn) == StringType))){ return listutils::typeError("file name not constant"); } // read file name string fileName; if(nl->AtomType(fn) == TextType){ fileName = nl->Text2String(fn); } if(nl->AtomType(fn) == StringType){ fileName = nl->StringValue(fn); } //second arguments must be of a type //Rectangle (dim={1, 2, 3, 4, 8}) //or SPATIAL2D or SPATIAL3D ListExpr argRect = nl->Second(args); bool ok = false; string errMsg; if (listutils::isKind(nl->First(argRect), Kind::SPATIAL1D())){ ok = checkHeader<1>(fileName, errMsg); } if (listutils::isKind(nl->First(argRect), Kind::SPATIAL2D())){ ok = checkHeader<2>(fileName, errMsg); } if (listutils::isKind(nl->First(argRect), Kind::SPATIAL3D())){ ok = checkHeader<3>(fileName, errMsg); } if (listutils::isKind(nl->First(argRect), Kind::SPATIAL4D())){ ok = checkHeader<4>(fileName, errMsg); } if (listutils::isKind(nl->First(argRect), Kind::SPATIAL8D())){ ok = checkHeader<8>(fileName, errMsg); } if(!ok){ return listutils::typeError(errMsg); } return nl->TwoElemList( listutils::basicSymbol >(), listutils::basicSymbol() ); } /* Operator createfrtree */ ListExpr createfrtreeTM(ListExpr args){ string err = "stream(Tuple(X)) x string x a_i1 x a_i2 x int expected"; if(!nl->HasLength(args,5)){ return listutils::typeError(err); } if (!Stream::checkType(nl->First(args))){ return listutils::typeError("Error in first argument." "Stream of tuples expected."); } if (!CcString::checkType(nl->Second(args)) && !FText::checkType(nl->Second(args))) return listutils::typeError("Error in second argument. " "string or text expected."); if(!listutils::isSymbol(nl->Third(args))){ return listutils::typeError("Error in third argument. " "Attribute name expected."); } if(!listutils::isSymbol(nl->Fourth(args))){ return listutils::typeError("Error in fourth argument. " "Attribute name expected"); } if(!CcInt::checkType(nl->Fifth(args))){ return listutils::typeError("Error in fifth argument. " "int as argument expected."); } string name1 = nl->SymbolValue(nl->Third(args)); ListExpr attrList = nl->Second(nl->Second(nl->First(args))); ListExpr type1; int index1 = listutils::findAttribute(attrList, name1, type1); if(index1==0){ return listutils::typeError("Attribute " + name1 + " unknown in tuple"); } if(!listutils::isKind(type1, Kind::SPATIAL1D()) && !listutils::isKind(type1, Kind::SPATIAL2D()) && !listutils::isKind(type1, Kind::SPATIAL3D()) && !listutils::isKind(type1, Kind::SPATIAL4D()) && !listutils::isKind(type1, Kind::SPATIAL8D())) { return listutils::typeError("Attribute " + name1 + " not of kind" + "SPATIAL1D, SPATIAL2D, SPATIAL3D, SPATIAL4D " + "or SPATIAL8D"); } string name2 = nl->SymbolValue(nl->Fourth(args)); ListExpr type2; int index2 = listutils::findAttribute(attrList, name2, type2); if(index2==0){ return listutils::typeError("Attribute " + name2 + " unknown in tuple"); } if(!TupleIdentifier::checkType(type2) ){ return listutils::typeError("Attribute " + name2 + " not of type " + TupleIdentifier::BasicType()); } return nl->ThreeElemList(nl->SymbolAtom(Symbols::APPEND()), nl->TwoElemList(nl->IntAtom(index1 - 1), nl->IntAtom(index2 - 1)), nl->First(args)); } //end of TM for Operator createfrtree////////// //Operator: insertfrtree/////////////////////// ListExpr InsertfrtreeTM(ListExpr args){ NList type(args); if (!type.hasLength(4)) { return NList::typeError("Expecting four arguments."); } NList streamType = type.first().first(); if (!isTupleStream(streamType.listExpr())) { return NList::typeError("Error in first argument! " "Stream of tuples expected."); } NList pathType = type.second().first(); bool isPathText; if (CcString::checkType(pathType.listExpr())) { isPathText = false; } else if (FText::checkType(pathType.listExpr())) { isPathText = true; } else { return NList::typeError("Error in second argument! " "String or text expected!"); } NList indexAttrNameType = type.third().first(); if (!indexAttrNameType.isSymbol()) { return NList::typeError("Error in third argument! " "Attribute name expected. " "Perhaps the attribute's name may be the name " "of a Secondo object!"); } string indexAttrName = indexAttrNameType.str(); ListExpr attributeList = streamType.second().second().listExpr(), attrType = nl->Empty(); int indexAttrIndex = FindAttribute(attributeList, indexAttrName, attrType); indexAttrIndex--; if (indexAttrIndex < 0) { return NList::typeError("Error in third argument!" "Attribute name '" + indexAttrName + "' not found!"); } NList idAttrNameType = type.fourth().first(); if (!idAttrNameType.isSymbol()) { return NList::typeError("Error in fourth argument! " "Attribute name expected. " "Perhaps the attribute's name may be the name " "of a Secondo object!"); } string idAttrName = idAttrNameType.str(); attrType = nl->Empty(); int idAttrIndex = FindAttribute(attributeList, idAttrName, attrType); idAttrIndex--; if (idAttrIndex < 0) { return NList::typeError("Error in fourth argument!" "Attribute name '" + indexAttrName + "' not found!"); } string path = type.second().second().str(); char* pathCopy = new char[path.length() + 1]; memcpy(pathCopy, path.c_str(), path.length() + 1); delete [] pathCopy; return NList(NList(Symbol::APPEND()), NList(NList(isPathText), NList(indexAttrIndex), NList(idAttrIndex)), streamType).listExpr(); } //end of TM for Operator insertfrtree////// //Operator deletefrtree///////////////////////////////////////////////////// ListExpr deletefrtreeTM(ListExpr args){ //identical to insertfrtree return InsertfrtreeTM(args); } //end of TM for Operator deletefrtree////////// // TM for frebuildtree ////////////////// ListExpr rebuildfrtreeTM( ListExpr args ) { string dat1; string dat2; string err = "string/text x string/text"; if (!nl->HasLength( args, 2 )) { return listutils::typeError(err + ": wrong number of arguments"); } ListExpr arg1 = nl->First(args); ListExpr arg2 = nl->Second(args); // Check first argument (name of source file) //if ( !( CcString::checkType(args.first().first()) if ( !( CcString::checkType(nl->First(arg1)) || FText::checkType(nl->First(arg1)))) { return NList::typeError(err + ": First argument is not string or text!"); } if ( !( nl -> AtomType(nl->Second(arg1)) == StringType || nl -> AtomType(nl->Second(arg1)) == TextType) ) { return NList::typeError(err + ": First argument is not string or text!"); } if ( nl -> AtomType(nl->Second(arg1)) == StringType ) { dat1 = nl->StringValue(nl->Second(arg1)); } if ( nl -> AtomType(nl->Second(arg1)) == TextType ) { dat1 = nl->Text2String(nl->Second(arg1)); } /* if (dat1.substr(dat1.size()-5, 4) != ".bin") { return NList::typeError(err + ": First argument hasn't extension .bin!"); } */ // Check if source file exists and can be opened std::ifstream file01; file01.open(dat1.c_str()); if (!file01) { return NList::typeError(err + ": First file couldn't be opened!"); } else { file01.close(); } // Check if source file contains R-Tree // creation of a dummy tree with dim = 1 /* RTree<1>* r1 = RTree<1>::OpenRebuild(dat1.c_str(), 50); if ((r1->GetHeader())->GetMarker() != '1') { return NList::typeError(err + ": First file doesn't contain an R-Tree!"); } delete r1;*/ /* Check dimension of the RTree * contained in the file that was passed. If the file does not contain an RTree an error message will be returned*/ const char * c = dat1.c_str(); int dim = checkDimension(c); /* If the first file contains an RTree we will need * to check whether its dimension is actually * covered*/ if (dim < 1 || dim > 8) { return NList::typeError (err + ": First file doesn't contain a valid R-Tree!"); } if (dim == 5 || dim == 6 || dim == 7) { return NList::typeError (err + ": First file doesn't contain a valid R-Tree!"); } // Check second argument (name of target file) if ( !( CcString::checkType(nl->First(arg2)) || FText::checkType(nl->First(arg2)))) { return NList::typeError(err + ": Second argument is not string or text!"); } if ( !( nl -> AtomType(nl->Second(arg2)) == StringType || nl -> AtomType(nl->Second(arg2)) == TextType) ) { return NList::typeError(err + ": Second argument is not string or text!"); } if ( nl -> AtomType(nl->Second(arg2)) == StringType ) { // dat2 = nl->SymbolValue(nl->Second(arg2)); dat2 = nl->StringValue(nl->Second(arg2)); } if ( nl -> AtomType(nl->Second(arg2)) == TextType ) { dat2 = nl->Text2String(nl->Second(arg2)); } /* if (dat2.substr(dat2.size()-5, 4) != ".bin") { return NList::typeError(err + ": Second argument hasn't extension .bin!"); } */ ListExpr resType = listutils::basicSymbol(); return nl->ThreeElemList( nl->SymbolAtom(Symbol::APPEND()), nl->TwoElemList(nl->TextAtom(dat1), nl->TextAtom(dat2)), resType ); } //end of TM for Operator rebuildfrtree//////// // 2. ValueMapping /* Operator ~fwindowintersect~ */ template int fWindowIntersectValMap ( Word* args, Word& result, int message, Word& local, Supplier s ) { //define RTreeIterator* //it will used as localInfo-class RTreeIterator* rti = (RTreeIterator *)local.addr; switch (message) { case OPEN:{ if (rti) delete rti; //read file string fileName = ((Attribute*)args[0].addr)->toText(); StandardSpatialAttribute* arg = (StandardSpatialAttribute*) args[1].addr; Rectangle rectArg = arg->BoundingBox(); //create R-Tree and Iterator RTree* rtree = RTree::Open(fileName.c_str(), 0); rti = new RTreeIterator(rtree, rectArg); local.addr = rti; return 0; }// end of OPEN case REQUEST:{ size_t id = rti->Search(); if (id != 0){ //Falls Suche noch nicht zu Ende ist TupleIdentifier* tid = new TupleIdentifier( true, id ); result.addr = tid; return YIELD; } else{ //Ende des Baums erreicht result.addr = 0; return CANCEL; } }//end of REQUEST case CLOSE:{ if (rti){ delete rti; local.addr = 0; } return 0; }//end of CLOSE }//end of switch(message) //should never happen return -1; } //ValueMapping function: createfrtree template int createfrtreeValMap ( Word* args, Word& result, int message, Word& local, Supplier s ) { Stream stream(args[0]); switch (message) { case OPEN:{ // writing the file for the RTree string filename = ((Attribute*)args[1].addr)->toText(); int min = ((CcInt*)args[4].addr)->GetValue(); try{ local.addr = RTree::Create(filename.c_str(), 512, min); } catch (exception& e){ cerr << "Creation failed: " << e.what() << '\n'; return CANCEL; } qp->Open(args[0].addr); break; } case REQUEST:{ if (local.addr != NULL){ Word tupleWord(Address(NULL)); qp->Request(args[0].addr, tupleWord); if(qp->Received(args[0].addr)){ int index1 = ((CcInt*)args[5].addr)->GetValue(), index2 = ((CcInt*) args[6].addr)->GetValue(); Tuple* tuple = (Tuple*)tupleWord.addr; StandardSpatialAttribute* value = (StandardSpatialAttribute*)tuple->GetAttribute(index1); TupleIdentifier* id = (TupleIdentifier*)tuple->GetAttribute(index2); try{ ((RTree*)local.addr)->Insert(value->BoundingBox(), (size_t)id->GetTid()); } catch(exception& e){ cerr << "Insertion failed: " << e.what() << '\n'; } result = tupleWord; return YIELD; } } result.addr = NULL; return CANCEL; } case CLOSE:{ qp->Close(args[0].addr); if (local.addr != NULL){ delete((RTree*)local.addr); local.addr = NULL; } break; } } return 0; } // end of VM function for createfrtree ////////////////////////////////// // Value Mapping function for insertfrtree ///////////////////////////// template int insertfrtreeValMap(Word* args, Word& result, int message, Word& local, Supplier s) { Stream stream(args[0]); switch (message) { case OPEN:{ string filename = ((Attribute*)args[1].addr)->toText(); try{ local.addr = RTree::Open(filename.c_str(), 50); } catch (exception& e){ cerr << "Opening failed: " << e.what() << '\n'; return CANCEL; } qp->Open(args[0].addr); break; } case REQUEST:{ if (local.addr != NULL){ Word tupleWord(Address(NULL)); qp->Request(args[0].addr, tupleWord); if(qp->Received(args[0].addr)){ int index1 = ((CcInt*)args[5].addr)->GetValue(), index2 = ((CcInt*) args[6].addr)->GetValue(); Tuple* tuple = (Tuple*)tupleWord.addr; StandardSpatialAttribute* value = (StandardSpatialAttribute*)tuple->GetAttribute(index1); TupleIdentifier* id = (TupleIdentifier*)tuple->GetAttribute(index2); try{ ((RTree*)local.addr)->Insert(value->BoundingBox(), (size_t)id->GetTid()); } catch(exception& e){ cerr << "Insertion failed: " << e.what() << '\n'; } //cout << ((RTree*)local.addr)->ToString() << '\n'; result = tupleWord; return YIELD; } } result.addr = NULL; return CANCEL; } case CLOSE:{ qp->Close(args[0].addr); if (local.addr != NULL){ delete((RTree*)local.addr); local.addr = NULL; } break; } } return 0; } // end of VM function for insertfrtree ////////////////////////////////// // Value Mapping function for deletefrtree ///////////////////////////// template int deletefrtreeValMap(Word* args, Word& result, int message, Word& local, Supplier s) { Stream stream(args[0]); switch (message) { case OPEN:{ string filename = ((Attribute*)args[1].addr)->toText(); try{ local.addr = RTree::Open(filename.c_str(), 512); } catch (exception& e){ cerr << "Opening failed: " << e.what() << '\n'; return CANCEL; } qp->Open(args[0].addr); break; } case REQUEST:{ if (local.addr != NULL){ Word tupleWord(Address(NULL)); qp->Request(args[0].addr, tupleWord); if(qp->Received(args[0].addr)){ int index1 = ((CcInt*)args[5].addr)->GetValue(), index2 = ((CcInt*) args[6].addr)->GetValue(); Tuple* tuple = (Tuple*)tupleWord.addr; StandardSpatialAttribute* value = (StandardSpatialAttribute*)tuple->GetAttribute(index1); TupleIdentifier* id = (TupleIdentifier*)tuple->GetAttribute(index2); try{ ((RTree*)local.addr)->Delete(value->BoundingBox(), (size_t)id->GetTid()); } catch(exception& e){ cerr << "Deletion failed: " << e.what() << '\n'; } //cout << ((RTree*)local.addr)->ToString() << '\n'; result = tupleWord; return YIELD; } } result.addr = NULL; return CANCEL; } case CLOSE:{ qp->Close(args[0].addr); if (local.addr != NULL){ delete((RTree*)local.addr); local.addr = NULL; } break; } } return 0; } // end of VM function for deletefrtree ////////////////////////////////// // Value Mapping for rebuildfrtree int rebuildfrtreeValMap (Word* args, Word& result, int message, Word& local, Supplier s) { // Parameters 2 and 3 are delivered from the type mapping function // in text format, params 0 and 1 can thus be neglected FText* pre1 = (FText*) args[2].addr; // get the argument and cast it FText* pre2 = (FText*) args[3].addr; // get the argument and cast it // Cast file names to string (and later to char* for ctor) string dat1 = (pre1->GetValue()).c_str(); string dat2 = (pre2->GetValue()).c_str(); const char * c = dat1.c_str(); int dim = checkDimension(c); if (dim == 1){ RTree<1>* rtree = RTree<1>::Open(c, 512); rtree->RebuildR(dat2.c_str()); delete rtree; } if (dim == 2){ RTree<2>* rtree = RTree<2>::Open(c, 512); rtree->RebuildR(dat2.c_str()); delete rtree; } if (dim == 3){ RTree<3>* rtree = RTree<3>::Open(c, 512); rtree->RebuildR(dat2.c_str()); delete rtree; } if (dim == 4){ RTree<4>* rtree = RTree<4>::Open(c, 512); rtree->RebuildR(dat2.c_str()); delete rtree; } if (dim == 8){ RTree<8>* rtree = RTree<8>::Open(c, 512); rtree->RebuildR(dat2.c_str()); delete rtree; } // rtree->RebuildR(dat2.c_str()); // delete rtree; // Delete source file //remove(dat1.c_str()); result = qp->ResultStorage(s); // use the result storage CcBool* b = static_cast (result.addr); // cast the result b->Set(true, true); // compute and set the result return 0; } // end of VM for rebuldfrtree // 4. Selection Function /////////// createfrtree ///////////////////////////////////////// int createfrtreeSelect (ListExpr args){ //int index = nl->Sixth(args); ListExpr attrList = nl->Second(nl->Second(nl->First(args))); string name = nl->SymbolValue(nl->Third(args)); ListExpr type; int index = listutils::findAttribute(attrList,name,type); assert(index > 0); //assert(index >0); if(listutils::isKind(type, Kind::SPATIAL1D())){ return 0; } if(listutils::isKind(type, Kind::SPATIAL2D())){ return 1; } if(listutils::isKind(type, Kind::SPATIAL3D())){ return 2; } if(listutils::isKind(type, Kind::SPATIAL4D())){ return 3; } if(listutils::isKind(type, Kind::SPATIAL8D())){ return 4; } return -1; } /////////// end of selection function for createfrtree ////////// // 5. Arrays for ValueMapping /////////// createfrtree ///////////////////////////////////////// ValueMapping createfrtreeVM[] = { createfrtreeValMap<1>, createfrtreeValMap<2>, createfrtreeValMap<3>, createfrtreeValMap<4>, createfrtreeValMap<8> }; ValueMapping insertfrtreeVM[] = { insertfrtreeValMap<1>, insertfrtreeValMap<2>, insertfrtreeValMap<3>, insertfrtreeValMap<4>, insertfrtreeValMap<8> }; ValueMapping deletefrtreeVM[] = { deletefrtreeValMap<1>, deletefrtreeValMap<2>, deletefrtreeValMap<3>, deletefrtreeValMap<4>, deletefrtreeValMap<8> }; /////////// end of VM array for createfrtree //////////////////// // 6. Operator Spec OperatorSpec createfrtreeSpec( "stream(tuple(X))x{txt,str}xIdxIdxint->stream(tpl(X))", "createfrtree(_,_,_,_,_) ", "creates an Rtree file", "query createfrtree()" ); OperatorSpec insertfrtreeSpec( "stream(tuple(X))x{txt,str}xIdxId->stream(tpl(X))", "insertfrtree(_,_,_,_) ", "performs inserts into an Rtree file", "query insertfrtree()" ); OperatorSpec deletefrtreeSpec( "stream(tuple(X))x{txt,str}xIdxId->stream(tpl(X))", "deletefrtree(_,_,_,_) ", "performs delete operations on a Rtree file", "query deletefrtree()" ); OperatorSpec rebuildfrtreeSpec( "file{txt,str}xfile{txt,str}-> bool", "rebuildfrtree(_,_) ", "rebuilds an RTree and creates a new RTree file", "query rebuildfrtree(oldfile.bin, newfile.bin )" ); // 7. Operator Instance Operator createfrtreeOp( "createfrtree", createfrtreeSpec.getStr(), 5, createfrtreeVM, createfrtreeSelect, createfrtreeTM ); Operator insertfrtreeOp( "insertfrtree", insertfrtreeSpec.getStr(), 5, insertfrtreeVM, createfrtreeSelect, InsertfrtreeTM ); Operator deletefrtreeOp( "deletefrtree", deletefrtreeSpec.getStr(), 5, deletefrtreeVM, createfrtreeSelect, deletefrtreeTM ); Operator rebuildfrtreeOp( "rebuildfrtree", rebuildfrtreeSpec.getStr(), rebuildfrtreeValMap, // createfrtreeSelect, Operator::SimpleSelect, rebuildfrtreeTM ); OperatorSpec fWindowIntersectSpec( "{txt, string}xR->stream(tid)", "_fwindowintersects(_)", "performs search in a Rtree index-file", "query fwindowintersects['strassen_GeoData_rtree', rectan] count" ); ValueMapping fWindowIntersectVMA[] = { fWindowIntersectValMap<1>, fWindowIntersectValMap<2>, fWindowIntersectValMap<3>, fWindowIntersectValMap<4>, fWindowIntersectValMap<8> }; int fWindowIntersectSelect (ListExpr args){ if(listutils::isKind(nl->Second(args), Kind::SPATIAL1D())){ return 0; } if (listutils::isKind(nl->Second(args), Kind::SPATIAL2D())){ return 1; } if(listutils::isKind(nl->Second(args), Kind::SPATIAL3D())){ return 2; } if(listutils::isKind(nl->Second(args), Kind::SPATIAL4D())){ return 3; } if(listutils::isKind(nl->Second(args), Kind::SPATIAL8D())){ return 4; } //should never be reached return -1; } Operator fWindowIntersectOp( "fwindowintersects", fWindowIntersectSpec.getStr(), 5, fWindowIntersectVMA, fWindowIntersectSelect, fWindowIntersectTM ); // // RTree Bulkload // // Value mapping select function int bulkloadfrtreeSelect( ListExpr a ) { // args: // ( // (stream (tuple ((Rectangle rect) (TID tid)))) // text // Rectangle // TID // int // real // ) NList args( a ); NList argStream = args.first(); NList argKeyName = args.third(); ListExpr attrList = argStream.second().second().listExpr(); string keyAttrName = argKeyName.str(); ListExpr keyAttrType = nl->Empty(); FindAttribute( attrList, keyAttrName, keyAttrType ); int res = -1; if ( listutils::isKind( keyAttrType, Kind::SPATIAL1D() ) ) res = 0; else if ( listutils::isKind( keyAttrType, Kind::SPATIAL2D() ) ) res = 1; else if ( listutils::isKind( keyAttrType, Kind::SPATIAL3D() ) ) res = 2; else if ( listutils::isKind( keyAttrType, Kind::SPATIAL4D() ) ) res = 3; else if ( listutils::isKind( keyAttrType, Kind::SPATIAL8D() ) ) res = 4; return res; } // // Type mapping ListExpr bulkloadfrtreeTM( ListExpr args ) { // args: // ( // ((stream (tuple ((Rectangle rect) (TID tid)))) (feed tmp1_tid)) // (text 'ix_rtree.bin') // (Rectangle Rectangle) // (TID TID) // (int 2) // (int 0) // ) // log //cout << "bulkloadfrtreeTM( " << nl->ToString( args ) << " )" << endl; NList type( args ); // Do some checks // // Length check if ( !type.hasLength( 6 ) ) return NList::typeError( "Expecting six arguments" ); // 1: Stream NList argStream = type.first(); // 2: File NList argFile = type.second(); // 3: Key-Type NList argKeyName = type.third(); // 4: TID NList argTidName = type.fourth(); // 5: Int - Min. fill NList argMinFill = type.fifth(); // 6: Int - Max. distance NList argMaxDist = type.sixth(); // Length if ( !argStream.hasLength( 2 ) || !argFile.hasLength( 2 ) || !argKeyName.hasLength( 2 ) || !argTidName.hasLength( 2 ) || !argMinFill.hasLength( 2 ) || !argMaxDist.hasLength( 2 ) ) return NList::typeError( "internal error" ); // Type checks if ( !Stream::checkType( argStream.first().listExpr() ) ) return NList::typeError( "Stream of tuples expected" ); // if ( !CcString::checkType( argFile.first().listExpr() ) && !FText::checkType( argFile.first().listExpr() ) ) return NList::typeError( "String or Text in first argument expected" ); // if ( !CcInt::checkType( argMinFill.first().listExpr() ) ) return NList::typeError( "Integer in fourth argument expected" ); // if ( !CcReal::checkType( argMaxDist.first().listExpr() ) ) return NList::typeError( "Real in fifth argument expected" ); // // Check attributes // if ( !argKeyName.first().isSymbol() ) return NList::typeError( "Attribute name in second argument expected" ); if ( !argTidName.first().isSymbol() ) return NList::typeError( "Attribute name in third argument expected" ); ListExpr attrList = argStream.first().second().second().listExpr(); // Key string keyAttrName = argKeyName.first().str(); ListExpr keyAttrType = nl->Empty(); int keyAttrIndex = FindAttribute( attrList, keyAttrName, keyAttrType ); if ( keyAttrIndex <= 0 ) NList::typeError( "Attribute name '" + keyAttrName + "' not found" ); // TID string tidAttrName = argTidName.first().str(); ListExpr tidAttrType = nl->Empty(); int tidAttrIndex = FindAttribute( attrList, tidAttrName, tidAttrType ); if ( tidAttrIndex <= 0 ) NList::typeError( "Attribute name '" + tidAttrName + "' not found" ); // // Check attribute types if ( !TupleIdentifier::checkType( tidAttrType ) ) return NList::typeError( "Attribute '" + tidAttrName + "' is no TupleIdentifier" ); if ( !listutils::isKind( keyAttrType, Kind::SPATIAL1D() ) && !listutils::isKind( keyAttrType, Kind::SPATIAL2D() ) && !listutils::isKind( keyAttrType, Kind::SPATIAL3D() ) && !listutils::isKind( keyAttrType, Kind::SPATIAL4D() ) && !listutils::isKind( keyAttrType, Kind::SPATIAL8D() ) ) return NList::typeError( "Attribute '" + keyAttrName + "' is not of kind SPATIAL1D, SPATIAL2D, SPATIAL3D, " "SPATIAL3D or SPATIAL8D" ); // // check file for existance string indexFile = argFile.second().str(); ifstream f( indexFile.c_str() ); if ( f.good() ) { f.close(); return NList::typeError( "File '" + indexFile + "' already exists" ); } else { f.close(); } // Result NList append; // (i i) append.append( nl->IntAtom( keyAttrIndex - 1 ) ); append.append( nl->IntAtom( tidAttrIndex - 1 ) ); // ListExpr res = NList( // (APPEND) NList( Symbol::APPEND() ), // append append, // (stream(tupel(..))) argStream.first() ).listExpr(); return res; } // // Value mapping function template int bulkloadfrtreeVM( Word* args, Word& result, int message, Word& local, Supplier s ) { // args // 0 : stream(tuple( .. )) // 1 : text - Filename // 2 : Symbol - Key Attribute Name // 3 : Symbol - TID Attribute Name // 4 : int - Min. filling // 5 : real - Max. distance // 6 : int - Key Attribute Index // 7 : int - TID Attr Index RTree* tree = static_cast*>( local.addr ); switch( message ) { case OPEN: { if ( tree != 0 ) delete tree; string indexFile = ((Attribute*)args[1].addr)->toText(); int minFilling = StdTypes::GetInt( args[4].addr ); CcReal* maxDistanceAttr = static_cast( args[5].addr ); double maxDistance = maxDistanceAttr->IsDefined() ? maxDistanceAttr->GetValue() : 0.0; if ( minFilling < 0 ) minFilling = 0; // Create tree and start bulkload process try { tree = RTree::Create( indexFile.c_str(), 1024, minFilling ); tree->BeginBulkload( maxDistance ); local.addr = tree; } catch( exception& ex ) { cerr << "Creation failed: " << ex.what() << endl; return CANCEL; } // catch // Open stream qp->Open( args[0].addr ); return 0; } // case OPEN case REQUEST: { if ( local.addr == 0 ) return CANCEL; // Request next element in stream Word tupleWord( Address( NULL ) ); qp->Request( args[0].addr, tupleWord ); if ( qp->Received( args[0].addr ) ) { Tuple* tuple = (Tuple*)tupleWord.addr; int keyAttrIndex = StdTypes::GetInt( args[6].addr ); int tidAttrIndex = StdTypes::GetInt( args[7].addr ); Attribute* keyAttr = tuple->GetAttribute( keyAttrIndex ); StandardSpatialAttribute* key = (StandardSpatialAttribute*)keyAttr; TupleIdentifier* tidAttr = (TupleIdentifier*)tuple->GetAttribute( tidAttrIndex ); TupleId tid = tidAttr->GetTid(); try { tree->Bulkload( key->BoundingBox(), (size_t)tid ); } catch( exception& ex ) { cerr << "Bulkload error: " << ex.what() << endl; return CANCEL; } // catch result.setAddr( tupleWord.addr ); return YIELD; } else { // End of stream reached result.addr = NULL; return CANCEL; } // else } // case REQUEST case CLOSE: { // close stream qp->Close( args[0].addr ); if ( local.addr != 0 ) { // End bulkload, cleanup tree->EndBulkload(); // log //cout << tree->ToString() << endl; delete tree; local.addr = NULL; } // if return 0; } // case CLOSE; default: { // should never happen return -1; } // default; } // switch } // // Value mapping array ValueMapping bulkloadfrtreeVMA[] = { bulkloadfrtreeVM<1>, bulkloadfrtreeVM<2>, bulkloadfrtreeVM<3>, bulkloadfrtreeVM<4>, bulkloadfrtreeVM<8> }; // // OperatorSpecs OperatorSpec bulkloadfrtreeOperatorSpec( "stream( tuple( X ) ) x {text, string} x Ident x" "Ident x int x real -> stream( tuple( X ) )", "_ bulkloadfrtree [_, _, _, _, _]", "creates a file based R-Tree index with bulkload", "query buildings feed addid bulkloadfrtree" "['index.bin', Rect, TID, 10, 5.0] count" ); // // Operators Operator bulkloadfrtreeOp( "bulkloadfrtree", bulkloadfrtreeOperatorSpec.getStr(), 5, bulkloadfrtreeVMA, // value mapping array bulkloadfrtreeSelect, // select function bulkloadfrtreeTM // type mapping ); /* Definition of the algebra */ class FileIndexAlgebra : public Algebra{ public: FileIndexAlgebra() : Algebra(){ //AddOperator (&ftestOp); //AddOperator (&ftestOp); AddOperator (&createfrtreeOp); createfrtreeOp.SetUsesMemory(); AddOperator (&fWindowIntersectOp); fWindowIntersectOp.SetUsesMemory(); fWindowIntersectOp.SetUsesArgsInTypeMapping(); AddOperator (&rebuildfrtreeOp); rebuildfrtreeOp.SetUsesMemory(); rebuildfrtreeOp.SetUsesArgsInTypeMapping(); // rebuildfbtreeOp.SetUsesArgsInTypeMapping(); AddOperator (&insertfrtreeOp); insertfrtreeOp.SetUsesMemory(); insertfrtreeOp.SetUsesArgsInTypeMapping(); //AddOperator (&FWindowintersectsOp); AddOperator (&deletefrtreeOp); deletefrtreeOp.SetUsesMemory(); deletefrtreeOp.SetUsesArgsInTypeMapping(); // // R-Tree bulkload // AddOperator( &bulkloadfrtreeOp ); bulkloadfrtreeOp.SetUsesArgsInTypeMapping(); bulkloadfrtreeOp.SetUsesMemory(); // // BPTree operators // // Createfbtree AddOperator( &BPTreeOperators::GetCreatefbtreeOperator() ); // Rebuildfbtree AddOperator( &BPTreeOperators::GetRebuildfbtreeOperator() ); // Deletefbtree AddOperator( &BPTreeOperators::GetDeletefbtreeOperator() ); // Insertfbtree AddOperator( &BPTreeOperators::GetInsertfbtreeOperator() ); // Bulkloadfbtree AddOperator( &BPTreeOperators::GetBulkloadfbtreeOperator() ); // // frange Operator& frangeOp = BPTreeOperators::GetFrangeOperator(); AddOperator( &frangeOp ); frangeOp.SetUsesArgsInTypeMapping(); // fleftrange Operator& fleftrangeOp = BPTreeOperators::GetFleftrangeOperator(); AddOperator( &fleftrangeOp ); fleftrangeOp.SetUsesArgsInTypeMapping(); // frightrange Operator& frightrangeOp = BPTreeOperators::GetFrightrangeOperator(); AddOperator( &frightrangeOp ); frightrangeOp.SetUsesArgsInTypeMapping(); // fexactmatch Operator& fexactmatchOp = BPTreeOperators::GetFexactmatchOperator(); AddOperator( &fexactmatchOp ); fexactmatchOp.SetUsesArgsInTypeMapping(); } ~FileIndexAlgebra() {}; }; } // end of namespace /* Initialization of algebra */ extern "C" Algebra* InitializeFileIndexAlgebra( NestedList* nlRef, QueryProcessor* qpRef ){ nl = nlRef; qp =qpRef; return new fialgebra::FileIndexAlgebra; }