/* ---- 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{] [}}] //[TOC] [\tableofcontents] //[_] [\_] [1] Implementation of R-Tree Algebra July 2003, Victor Almeida October 2004, Herbert Schoenhammer, tested and divided in Header-File and Implementation-File. Also R-Trees with three and four dimensions are created. December 2005, Victor Almeida deleted the deprecated algebra levels (~executable~, ~descriptive~, and ~hibrid~). Only the executable level remains. Models are also removed from type constructors. February 2007, Christian Duentgen added operator for bulk loading R-trees. Also added several operators for rtree insprospection. October 2009, Christian Duentgen corrected type mapping for ~gettuples~ and ~gettuples2~ and replaced weird 'CHECK\_COND' macro in all type mappings. [TOC] 0 Overview This Algebra implements the creation of two-, three- and four-dimensional R-Trees. First the the type constructor ~rtree~, ~rtree3~ and ~rtree4~ are defined. Second the operator ~creatertree~ to build the trees is defined. This operator expects an attribute in the relation that implements the kind ~SPATIAL2D~, ~SPATIAL3D~, or ~SPATIAL4D~. Only the bounding boxes of the values of this attribute are indexed in the R-Tree. Finally, the operator ~windowintersects~ retrieves the tuples of the original relation which bounding boxes of the indexed attribute intersect the window (of type ~rect~, ~rect3~, or ~rect4~) given as argument to the operator. 1 Defines and Includes */ #include #include #include #include "RTreeAlgebra.h" #include "Algebras/Relation-C++/RelationAlgebra.h" #include "Algebras/Rectangle/RectangleAlgebra.h" #include "Algebras/TupleIdentifier/TupleIdentifier.h" #include "Algebras/FText/FTextAlgebra.h" #include "Algebra.h" #include "NestedList.h" #include "QueryProcessor.h" #include "StandardTypes.h" #include "CPUTimeMeasurer.h" #include "Messages.h" #include "Progress.h" #include "ListUtils.h" #include "AlmostEqual.h" #include "Symbols.h" #include "Stream.h" #include "LRU.h" extern NestedList* nl; extern QueryProcessor* qp; using namespace std; #define BBox Rectangle //using namespace temporalalgebra; /* Implementation of Functions and Procedures */ int myCompare( const void* a, const void* b ) { if( ((SortedArrayItem *) a)->pri < ((SortedArrayItem *) b)->pri ) return -1; else if( ((SortedArrayItem *) a)->pri > ((SortedArrayItem *) b)->pri ) return 1; else return 0; } /* 1 Type constructor ~rtree~ 1.1 Type property of type constructor ~rtree~ */ ListExpr RTree2Prop() { ListExpr examplelist = nl->TextAtom(); nl->AppendText(examplelist, " creatertree []" " where is the key of type rect"); return (nl->TwoElemList( nl->TwoElemList(nl->StringAtom("Creation"), nl->StringAtom("Example Creation")), nl->TwoElemList(examplelist, nl->StringAtom("(let myrtree = countries" " creatertree [boundary])")))); } /* 1.8 ~Check~-function of type constructor ~rtree~ 1.8.1 Auxiliary function for all RTree Versions */ bool CheckRTreeX(ListExpr type, ListExpr& errorInfo, const string & treeType, const string& indexKIND, const string& indexType) { AlgebraManager* algMgr; if((!nl->IsAtom(type)) && (nl->ListLength(type) == 4) && listutils::isSymbol(nl->First(type), treeType)) { algMgr = SecondoSystem::GetAlgebraManager(); return algMgr->CheckKind(Kind::TUPLE(), nl->Second(type), errorInfo) && (nl->IsEqual(nl->Third(type), indexType) || algMgr->CheckKind(indexKIND, nl->Third(type), errorInfo)) && nl->IsAtom(nl->Fourth(type)) && nl->AtomType(nl->Fourth(type)) == BoolType; } else { errorInfo = nl->Append(errorInfo, nl->ThreeElemList( nl->IntAtom(60), nl->SymbolAtom(treeType), type)); return false; } return true; } bool CheckRTree2(ListExpr type, ListExpr& errorInfo){ return CheckRTreeX(type, errorInfo,RTree2TID::BasicType(), Kind::SPATIAL2D(), Rectangle<2>::BasicType()); } /* 1.12 Type Constructor object for type constructor ~rtree3~ */ TypeConstructor rtree( RTree2TID::BasicType(), RTree2Prop, OutRTree<2>, InRTree<2>, 0, 0, CreateRTree<2>, DeleteRTree<2>, OpenRTree<2>, SaveRTree<2>, CloseRTree<2>, CloneRTree<2>, CastRTree<2>, SizeOfRTree<2>, CheckRTree2 ); /* 2 Type constructor ~rtree3~ 2.1 Type property of type constructor ~rtree3~ */ ListExpr RTree3Prop() { ListExpr examplelist = nl->TextAtom(); nl->AppendText(examplelist, " creatertree []" " where is the key of type rect3"); return (nl->TwoElemList( nl->TwoElemList(nl->StringAtom("Creation"), nl->StringAtom("Example Creation")), nl->TwoElemList(examplelist, nl->StringAtom("(let myrtree = countries" " creatrtree [boundary])")))); } /* 2.8 ~Check~-function of type constructor ~rtree3~ */ bool CheckRTree3(ListExpr type, ListExpr& errorInfo) { return CheckRTreeX(type, errorInfo,RTree3TID::BasicType(), Kind::SPATIAL3D(), Rectangle<3>::BasicType()); } /* 1.12 Type Constructor object for type constructor ~rtree3~ */ TypeConstructor rtree3( RTree3TID::BasicType(), RTree3Prop, OutRTree<3>, InRTree<3>, 0, 0, CreateRTree<3>, DeleteRTree<3>, OpenRTree<3>, SaveRTree<3>, CloseRTree<3>, CloneRTree<3>, CastRTree<3>, SizeOfRTree<3>, CheckRTree3 ); /* 3 Type constructor ~rtree4~ 3.1 Type property of type constructor ~rtree4~ */ ListExpr RTree4Prop() { ListExpr examplelist = nl->TextAtom(); nl->AppendText(examplelist, " creatertree []" " where is the key of type rect4"); return (nl->TwoElemList( nl->TwoElemList( nl->StringAtom("Creation"), nl->StringAtom("Example Creation")), nl->TwoElemList( examplelist, nl->StringAtom("(let myrtree = countries" " creatertree [boundary])")))); } /* 3.8 ~Check~-function of type constructor ~rtree4~ */ bool CheckRTree4(ListExpr type, ListExpr& errorInfo) { return CheckRTreeX(type, errorInfo,RTree4TID::BasicType(), Kind::SPATIAL4D(), Rectangle<4>::BasicType()); } /* 3.12 Type Constructor object for type constructor ~rtree~ */ TypeConstructor rtree4( RTree4TID::BasicType(), RTree4Prop, OutRTree<4>, InRTree<4>, 0, 0, CreateRTree<4>, DeleteRTree<4>, OpenRTree<4>, SaveRTree<4>, CloseRTree<4>, CloneRTree<4>, CastRTree<4>, SizeOfRTree<4>, CheckRTree4 ); /* 3 Type constructor ~rtree8~ 3.1 Type property of type constructor ~rtree8~ */ ListExpr RTree8Prop() { ListExpr examplelist = nl->TextAtom(); nl->AppendText(examplelist, " creatertree []" " where is the key of type rect8"); return (nl->TwoElemList( nl->TwoElemList( nl->StringAtom("Creation"), nl->StringAtom("Example Creation")), nl->TwoElemList( examplelist, nl->StringAtom("(let myrtree = countries" " creatertree [boundary])")))); } /* 3.8 ~Check~-function of type constructor ~rtree8~ */ bool CheckRTree8(ListExpr type, ListExpr& errorInfo) { return CheckRTreeX(type, errorInfo,RTree4TID::BasicType(), Kind::SPATIAL8D(), Rectangle<8>::BasicType()); } /* 3.12 Type Constructor object for type constructor ~rtree8~ */ TypeConstructor rtree8( RTree8TID::BasicType(), RTree8Prop, OutRTree<8>, InRTree<8>, 0, 0, CreateRTree<8>, DeleteRTree<8>, OpenRTree<8>, SaveRTree<8>, CloseRTree<8>, CloneRTree<8>, CastRTree<8>, SizeOfRTree<8>, CheckRTree8 ); /* 2 Type constructor ~rtree1~ 2.1 Type property of type constructor ~rtree1~ */ ListExpr RTree1Prop() { ListExpr examplelist = nl->TextAtom(); nl->AppendText(examplelist, " creatertree []" " where is the key of type rect1"); return (nl->TwoElemList( nl->TwoElemList(nl->StringAtom("Creation"), nl->StringAtom("Example Creation")), nl->TwoElemList(examplelist, nl->StringAtom("(let myrtree = countries" " creatrtree [boundary])")))); } /* 2.8 ~Check~-function of type constructor ~rtree1~ */ bool CheckRTree1(ListExpr type, ListExpr& errorInfo) { return CheckRTreeX(type, errorInfo,RTree1TID::BasicType(), Kind::SPATIAL1D(), Rectangle<1>::BasicType()); } /* 1.12 Type Constructor object for type constructor ~rtree3~ */ TypeConstructor rtree1( RTree1TID::BasicType(), RTree1Prop, OutRTree<1>, InRTree<1>, 0, 0, CreateRTree<1>, DeleteRTree<1>, OpenRTree<1>, SaveRTree<1>, CloseRTree<1>, CloneRTree<1>, CastRTree<1>, SizeOfRTree<1>, CheckRTree1 ); /* 7 Operators of the RTree Algebra 7.1 Operator ~creatertree~ The operator ~creatrtree~ creates a R-Tree for a given Relation. The exact type of the desired R-Tree is defind in RTreeAlgebra.h. The variables ~do\_linear\_split~, ~do\_quadratic\_split~ or ~do\_axis\_split~ are defining, whether a R-Tree (Guttman 84) or a R[*]-Tree is generated. The following operator ~creatertree~ accepts relations with tuples of (at least) one attribute of kind ~SPATIAL2D~, ~SPATIAL3D~ or ~SPATIAL4D~ or ~rect~, ~rect3~, and ~rect4~. The attribute name is specified as argument of the operator. 7.1.1 Type Mapping of operator ~creatertree~ */ ListExpr CreateRTreeTypeMap(ListExpr args) { // Check for correct general argument list format if(nl->IsEmpty(args) || !(nl->ListLength(args) == 2)){ return listutils::typeError("Expects exactly 2 arguments."); } ListExpr relDescription = nl->First(args), attrNameLE = nl->Second(args); if(!listutils::isSymbol(attrNameLE)){ return listutils::typeError("Expects key attribute name as 2nd argument."); } string attrName = (nl->SymbolValue(attrNameLE)); // Check for relation or tuplestream as first argument if( !( listutils::isRelDescription(relDescription) || listutils::isTupleStream(relDescription) ) ){ return listutils::typeError("Expects a relation or tulestream as 1st " "argument."); } // Test for index attribute ListExpr tupleDescription = nl->Second(relDescription); ListExpr attrList = nl->Second(tupleDescription); ListExpr attrType; int attrIndex = listutils::findAttribute(attrList, attrName, attrType); if(attrIndex <= 0){ return listutils::typeError("Expects key attribute (2nd argument) to be a " "member of the relation/ stream (1st argument)."); } if( !( listutils::isSpatialType(attrType) || listutils::isRectangle(attrType) ) ){ return listutils::typeError("Expects key attribute to be of kind SPATIAL," "SPATIAL3D, SPATIAL4D, SPATIAL8D, or have type rect, rect3, rect4, or " "rect8"); } string rtreetype; if ( listutils::isKind(attrType, Kind::SPATIAL2D()) || listutils::isSymbol(attrType, Rectangle<2>::BasicType())) rtreetype = RTree2TID::BasicType(); else if ( listutils::isKind(attrType, Kind::SPATIAL3D()) || listutils::isSymbol(attrType, Rectangle<3>::BasicType())) rtreetype = RTree3TID::BasicType(); else if ( listutils::isKind(attrType, Kind::SPATIAL4D()) || listutils::isSymbol(attrType, Rectangle<4>::BasicType())) rtreetype = RTree4TID::BasicType(); else if ( listutils::isKind(attrType, Kind::SPATIAL8D()) || listutils::isSymbol(attrType, Rectangle<8>::BasicType())) rtreetype = RTree8TID::BasicType(); else if ( listutils::isKind(attrType, Kind::SPATIAL1D()) || listutils::isSymbol(attrType, Rectangle<1>::BasicType())) rtreetype = RTree1TID::BasicType(); if( nl->IsEqual(nl->First(relDescription), Relation::BasicType()) ) { return nl->ThreeElemList( nl->SymbolAtom(Symbol::APPEND()), nl->OneElemList( nl->IntAtom(attrIndex)), nl->FourElemList( nl->SymbolAtom(rtreetype), tupleDescription, attrType, nl->BoolAtom(false))); } else // nl->IsEqual(nl->First(relDescription), Symbol::STREAM()) { /* Here we can have two possibilities: - multi-entry indexing, or - double indexing For multi-entry indexing, one and only one of the attributes must be a tuple identifier. In the latter, together with a tuple identifier, the last two attributes must be of integer type (~int~). In the first case, a standard R-Tree is created possibly containing several entries to the same tuple identifier, and in the latter, a double index R-Tree is created using as low and high parameters these two last integer numbers. */ ListExpr first, rest, newAttrList=nl->TheEmptyList(), lastNewAttrList=nl->TheEmptyList(); int tidIndex = 0; string type; bool firstcall = true, doubleIndex = false; int nAttrs = nl->ListLength( attrList ); rest = attrList; int j = 1; while (!nl->IsEmpty(rest)) { first = nl->First(rest); rest = nl->Rest(rest); type = nl->SymbolValue(nl->Second(first)); if (type == TupleIdentifier::BasicType()) { if(tidIndex != 0){ return listutils::typeError("Expects exactly one arribute of type " "'tid' within the 1st argument."); } tidIndex = j; } else if( j == nAttrs - 1 && type == CcInt::BasicType() && nl->SymbolValue( nl->Second(nl->First(rest))) == CcInt::BasicType() ) { // the last two attributes are integers doubleIndex = true; } else { if (firstcall) { firstcall = false; newAttrList = nl->OneElemList(first); lastNewAttrList = newAttrList; } else { lastNewAttrList = nl->Append(lastNewAttrList, first); } } j++; } if(tidIndex <= 0){ return listutils::typeError("Exects exactly one attribute of type 'tid'" " within 1st argument."); } return nl->ThreeElemList( nl->SymbolAtom(Symbol::APPEND()), nl->TwoElemList( nl->IntAtom(attrIndex), nl->IntAtom(tidIndex)), nl->FourElemList( nl->SymbolAtom(rtreetype), nl->TwoElemList( nl->SymbolAtom(Tuple::BasicType()), newAttrList), attrType, nl->BoolAtom(doubleIndex))); } } /* 4.1.2 Selection function of operator ~creatertree~ */ int CreateRTreeSelect (ListExpr args) { ListExpr relDescription = nl->First(args), attrNameLE = nl->Second(args), tupleDescription = nl->Second(relDescription), attrList = nl->Second(tupleDescription); string attrName = nl->SymbolValue(attrNameLE); ListExpr attrType; FindAttribute(attrList, attrName, attrType); AlgebraManager* algMgr = SecondoSystem::GetAlgebraManager(); ListExpr errorInfo = nl->OneElemList( nl->SymbolAtom( "ERRORS" ) ); int result; if ( algMgr->CheckKind(Kind::SPATIAL2D(), attrType, errorInfo) ) result = 0; else if ( algMgr->CheckKind(Kind::SPATIAL3D(), attrType, errorInfo) ) result = 1; else if ( algMgr->CheckKind(Kind::SPATIAL4D(), attrType, errorInfo) ) result = 2; else if ( algMgr->CheckKind(Kind::SPATIAL8D(), attrType, errorInfo) ) result = 3; else if ( algMgr->CheckKind(Kind::SPATIAL1D(), attrType, errorInfo) ) result = 4; else if( nl->SymbolValue(attrType) == Rectangle<2>::BasicType() ) result = 5; else if( nl->SymbolValue(attrType) == Rectangle<3>::BasicType() ) result = 6; else if( nl->SymbolValue(attrType) == Rectangle<4>::BasicType() ) result = 7; else if( nl->SymbolValue(attrType) == Rectangle<8>::BasicType() ) result = 8; else if( nl->SymbolValue(attrType) == Rectangle<1>::BasicType() ) result = 9; else return -1; /* should not happen */ if( nl->SymbolValue(nl->First(relDescription)) == Relation::BasicType()) return result; if( nl->SymbolValue(nl->First(relDescription)) == Symbol::STREAM()) { ListExpr first, rest = attrList; while (!nl->IsEmpty(rest)) { first = nl->First(rest); rest = nl->Rest(rest); } if( nl->IsEqual( nl->Second( first ), CcInt::BasicType() ) ) // Double indexing return result + 20; else // Multi-entry indexing return result + 10; } return -1; } /* 4.1.3 Value mapping function of operator ~creatertree~ */ template int CreateRTreeRelSpatial(Word* args, Word& result, int message, Word& local, Supplier s) { Relation* relation; int attrIndex; GenericRelationIterator* iter; Tuple* tuple; result = qp->ResultStorage(s); R_Tree*rtree = static_cast*>(result.addr); relation = (Relation*)args[0].addr; attrIndex = ((CcInt*)args[2].addr)->GetIntval() - 1; iter = relation->MakeScan(); while( (tuple = iter->GetNextTuple()) != 0 ) { if( ((StandardSpatialAttribute*)(tuple-> GetAttribute(attrIndex)))->IsDefined() ) { BBox box = ((StandardSpatialAttribute*)(tuple-> GetAttribute(attrIndex)))->BoundingBox(); if (box.IsDefined()) { R_TreeLeafEntry e( box, tuple->GetTupleId() ); rtree->Insert( e ); } } tuple->DeleteIfAllowed(); } delete iter; return 0; } template int CreateRTreeStreamSpatial(Word* args, Word& result, int message, Word& local, Supplier s) { Word wTuple; R_Tree *rtree = (R_Tree*)qp->ResultStorage(s).addr; result.setAddr( rtree ); int attrIndex = ((CcInt*)args[2].addr)->GetIntval() - 1, tidIndex = ((CcInt*)args[3].addr)->GetIntval() - 1; qp->Open(args[0].addr); qp->Request(args[0].addr, wTuple); while (qp->Received(args[0].addr)) { Tuple* tuple = (Tuple*)wTuple.addr; if( ((StandardSpatialAttribute*)tuple-> GetAttribute(attrIndex))->IsDefined() && ((TupleIdentifier *)tuple->GetAttribute(tidIndex))-> IsDefined() ) { BBox box = ((StandardSpatialAttribute*)tuple-> GetAttribute(attrIndex))->BoundingBox(); if (box.IsDefined()) { R_TreeLeafEntry e( box, ((TupleIdentifier *)tuple-> GetAttribute(tidIndex))->GetTid() ); rtree->Insert( e ); } } tuple->DeleteIfAllowed(); qp->Request(args[0].addr, wTuple); } qp->Close(args[0].addr); return 0; } template int CreateRTreeRelRect(Word* args, Word& result, int message, Word& local, Supplier s) { Relation* relation; int attrIndex; GenericRelationIterator* iter; Tuple* tuple; R_Tree *rtree = (R_Tree*)qp->ResultStorage(s).addr; result.setAddr( rtree ); relation = (Relation*)args[0].addr; attrIndex = ((CcInt*)args[2].addr)->GetIntval() - 1; iter = relation->MakeScan(); while( (tuple = iter->GetNextTuple()) != 0 ) { BBox *box = (BBox*)tuple->GetAttribute(attrIndex); if( box->IsDefined() ) { R_TreeLeafEntry e( *box, tuple->GetTupleId() ); rtree->Insert( e ); } tuple->DeleteIfAllowed(); } delete iter; return 0; } template int CreateRTreeStreamRect(Word* args, Word& result, int message, Word& local, Supplier s) { Word wTuple; R_Tree *rtree = (R_Tree*)qp->ResultStorage(s).addr; result.setAddr( rtree ); int attrIndex = ((CcInt*)args[2].addr)->GetIntval() - 1, tidIndex = ((CcInt*)args[3].addr)->GetIntval() - 1; qp->Open(args[0].addr); qp->Request(args[0].addr, wTuple); while (qp->Received(args[0].addr)) { Tuple* tuple = (Tuple*)wTuple.addr; if( ((StandardSpatialAttribute*)tuple-> GetAttribute(attrIndex))->IsDefined() && ((TupleIdentifier *)tuple->GetAttribute(tidIndex))-> IsDefined() ) { BBox *box = (BBox*)tuple->GetAttribute(attrIndex); if( box->IsDefined() ) { R_TreeLeafEntry e( *box, ((TupleIdentifier *)tuple-> GetAttribute(tidIndex))->GetTid() ); rtree->Insert( e ); } } tuple->DeleteIfAllowed(); qp->Request(args[0].addr, wTuple); } qp->Close(args[0].addr); return 0; } template int CreateRTree2LSpatial(Word* args, Word& result, int message, Word& local, Supplier s) { Word wTuple; R_Tree *rtree = (R_Tree*)qp->ResultStorage(s).addr; result.setAddr( rtree ); int attrIndex = ((CcInt*)args[2].addr)->GetIntval() - 1, tidIndex = ((CcInt*)args[3].addr)->GetIntval() - 1; qp->Open(args[0].addr); qp->Request(args[0].addr, wTuple); while (qp->Received(args[0].addr)) { Tuple* tuple = (Tuple*)wTuple.addr; if( ((StandardSpatialAttribute*)tuple-> GetAttribute(attrIndex))->IsDefined() && ((TupleIdentifier *)tuple->GetAttribute(tidIndex))-> IsDefined() && ((CcInt*)tuple->GetAttribute(tuple->GetNoAttributes()-2))-> IsDefined() && ((CcInt*)tuple->GetAttribute(tuple->GetNoAttributes()-1))-> IsDefined() ) { BBox box = ((StandardSpatialAttribute*)tuple-> GetAttribute(attrIndex))->BoundingBox(); if (box.IsDefined()) { R_TreeLeafEntry e(box, TwoLayerLeafInfo( ((TupleIdentifier *)tuple-> GetAttribute(tidIndex))->GetTid(), ((CcInt*)tuple-> GetAttribute(tuple->GetNoAttributes()-2))->GetIntval(), ((CcInt*)tuple-> GetAttribute(tuple->GetNoAttributes()-1))->GetIntval())); rtree->Insert( e ); } } tuple->DeleteIfAllowed(); qp->Request(args[0].addr, wTuple); } qp->Close(args[0].addr); return 0; } template int CreateRTree2LRect(Word* args, Word& result, int message, Word& local, Supplier s) { Word wTuple; R_Tree *rtree = (R_Tree*)qp->ResultStorage(s).addr; result.setAddr( rtree ); int attrIndex = ((CcInt*)args[2].addr)->GetIntval() - 1, tidIndex = ((CcInt*)args[3].addr)->GetIntval() - 1; qp->Open(args[0].addr); qp->Request(args[0].addr, wTuple); while (qp->Received(args[0].addr)) { Tuple* tuple = (Tuple*)wTuple.addr; if( ((StandardSpatialAttribute*)tuple-> GetAttribute(attrIndex))->IsDefined() && ((TupleIdentifier *)tuple->GetAttribute(tidIndex))-> IsDefined() && ((CcInt*)tuple->GetAttribute(tuple->GetNoAttributes()-2))-> IsDefined() && ((CcInt*)tuple->GetAttribute(tuple->GetNoAttributes()-1))-> IsDefined() ) { BBox *box = (BBox*)tuple->GetAttribute(attrIndex); if( box->IsDefined() ) { R_TreeLeafEntry e( *box, TwoLayerLeafInfo( ((TupleIdentifier *)tuple-> GetAttribute(tidIndex))->GetTid(), ((CcInt*)tuple->GetAttribute( tuple->GetNoAttributes()-2))->GetIntval(), ((CcInt*)tuple->GetAttribute( tuple->GetNoAttributes()-1))->GetIntval() ) ); rtree->Insert( e ); } } tuple->DeleteIfAllowed(); qp->Request(args[0].addr, wTuple); } qp->Close(args[0].addr); return 0; } /* 4.1.5 Definition of value mapping vectors */ ValueMapping rtreecreatertreemap [] = { CreateRTreeRelSpatial<2>, CreateRTreeRelSpatial<3>, CreateRTreeRelSpatial<4>, CreateRTreeRelSpatial<8>, CreateRTreeRelSpatial<1>, CreateRTreeRelRect<2>, CreateRTreeRelRect<3>, CreateRTreeRelRect<4>, CreateRTreeRelRect<8>, CreateRTreeRelRect<1>, CreateRTreeStreamSpatial<2>, CreateRTreeStreamSpatial<3>, CreateRTreeStreamSpatial<4>, CreateRTreeStreamSpatial<8>, CreateRTreeStreamSpatial<1>, CreateRTreeStreamRect<2>, CreateRTreeStreamRect<3>, CreateRTreeStreamRect<4>, CreateRTreeStreamRect<8>, CreateRTreeStreamRect<1>, CreateRTree2LSpatial<2>, CreateRTree2LSpatial<3>, CreateRTree2LSpatial<4>, CreateRTree2LSpatial<8>, CreateRTree2LSpatial<1>, CreateRTree2LRect<2>, CreateRTree2LRect<3>, CreateRTree2LRect<4>, CreateRTree2LRect<8>, CreateRTree2LRect<1>}; /* 4.1.6 Specification of operator ~creatertree~ */ const string CreateRTreeSpec = "( ( \"1st Signature\"" " \"Syntax\" \"Meaning\" " "\"Example\" ) " "( ((rel (tuple (x1 t1)...(xn tn)))) xi)" " -> (rtree (tuple ((x1 t1)...(xn tn))) ti false)\n" "((stream (tuple (x1 t1)...(xn tn) (id tid))) xi)" " -> (rtree (tuple ((x1 t1)...(xn tn))) ti false)\n" "((stream (tuple (x1 t1)...(xn tn) " "(id tid)(low int)(high int))) xi)" " -> (rtree (tuple ((x1 t1)...(xn tn))) ti true)" "_ creatertree [ _ ]" "Creates an rtree. The key type ti must " "be of kind SPATIAL2D, SPATIAL3D, SPATIAL4D or Spatial8D, " "or of type rect, rect2, rect3, rect4 or rect8." "let myrtree = Kreis feed extend[id: tupleid(.)] " "creatertree[Gebiet]" ") )"; /* 4.1.7 Definition of operator ~creatertree~ */ Operator creatertree ( "creatertree", // name CreateRTreeSpec, // specification 30, // Number of overloaded functions rtreecreatertreemap, // value mapping CreateRTreeSelect, // trivial selection function CreateRTreeTypeMap // type mapping ); /* 7.2 Operator ~windowintersects~ 7.2.1 Type mapping function of operator ~windowintersects~ */ ListExpr WindowIntersectsTypeMap(ListExpr args) { if( nl->IsEmpty(args) || nl->IsAtom(args) || nl->ListLength(args) != 3){ return listutils::typeError("Expects exactly 3 arguments."); } /* Split argument in three parts */ ListExpr rtreeDescription = nl->First(args); ListExpr relDescription = nl->Second(args); ListExpr searchWindow = nl->Third(args); // first must be an rtree if(!listutils::isRTreeDescription(rtreeDescription)){ return listutils::typeError("Expects 1st argument to be of type " "'rtree(,bool)'."); } // second a relation if(!listutils::isRelDescription(relDescription)){ return listutils::typeError("Expects 2nd argument to be of type " "'rel()'."); } // third a type with an MBR if(!( listutils::isSpatialType(searchWindow) || listutils::isRectangle(searchWindow))){ return listutils::typeError("Expects 3nd argument to be of a type of kind " "SPATIAL, SPATIAL3D, SPATIAL4D, SPATIAL8D; or of type 'rect', 'rect3', " "'rect4', or 'rect8'."); } // check that rtree and rel have the same associated tuple type ListExpr tupleDescription = nl->Second(relDescription), rtreeKeyType = nl->Third(rtreeDescription); if(!( listutils::isSpatialType(rtreeKeyType) || listutils::isRectangle(rtreeKeyType))){ return listutils::typeError("Expects key type of the rtree passed as " "1st argument to to be of a type of kind " "SPATIAL, SPATIAL3D, SPATIAL4D, SPATIAL8D; or of type 'rect', 'rect3', " "'rect4', or 'rect8'."); } // This test is omitted so that an R-tree built by bulk load // can be used with this operator. (RHG 13.6.2008) // ListExpr rtreeTupleDescription = nl->Second(rtreeDescription): //if(!(nl->Equal(rtreeTupleDescription, rtreeAttrList))){ // return listutils::typeError("Expects matching tuple-types for 1st and " // "2nd argument."); //} // Check whether key type and rtree dimension match if( !( (listutils::isKind(rtreeKeyType, Kind::SPATIAL2D()) && listutils::isSymbol(searchWindow, Rectangle<2>::BasicType())) || (listutils::isKind(rtreeKeyType, Kind::SPATIAL2D()) && listutils::isKind(searchWindow, Kind::SPATIAL2D())) || (listutils::isSymbol(searchWindow, Rectangle<2>::BasicType()) && listutils::isSymbol(rtreeKeyType, Rectangle<2>::BasicType())) ) && !( (listutils::isKind(rtreeKeyType, Kind::SPATIAL3D()) && listutils::isSymbol(searchWindow, Rectangle<3>::BasicType())) || (listutils::isKind(rtreeKeyType, Kind::SPATIAL3D()) && listutils::isKind(searchWindow, Kind::SPATIAL3D())) || (listutils::isSymbol(searchWindow, Rectangle<3>::BasicType()) && listutils::isSymbol(rtreeKeyType, Rectangle<3>::BasicType())) ) && !( (listutils::isKind(rtreeKeyType, Kind::SPATIAL4D()) && listutils::isSymbol(searchWindow, Rectangle<4>::BasicType())) || (listutils::isKind(rtreeKeyType, Kind::SPATIAL4D()) && listutils::isKind(searchWindow, Kind::SPATIAL4D())) || (listutils::isSymbol(searchWindow, Rectangle<4>::BasicType()) && listutils::isSymbol(rtreeKeyType, Rectangle<4>::BasicType())) ) && !( (listutils::isKind(rtreeKeyType, Kind::SPATIAL8D()) && listutils::isSymbol(searchWindow, Rectangle<8>::BasicType())) || (listutils::isKind(rtreeKeyType, Kind::SPATIAL8D()) && listutils::isKind(searchWindow, Kind::SPATIAL8D())) || (listutils::isSymbol(searchWindow, Rectangle<8>::BasicType()) && listutils::isSymbol(rtreeKeyType, Rectangle<8>::BasicType())) ) && !( (listutils::isKind(rtreeKeyType, Kind::SPATIAL1D()) && listutils::isSymbol(searchWindow, Rectangle<1>::BasicType())) || (listutils::isKind(rtreeKeyType, Kind::SPATIAL1D()) && listutils::isKind(searchWindow, Kind::SPATIAL1D())) || (listutils::isSymbol(searchWindow, Rectangle<1>::BasicType()) && listutils::isSymbol(rtreeKeyType, Rectangle<1>::BasicType())) ) ){ return listutils::typeError("Expects same dimensions for the rtree-type " "(1st argument) and for the key type (3rd argument)."); } return nl->TwoElemList( nl->SymbolAtom(Symbol::STREAM()), tupleDescription); } /* 5.1.2 Selection function of operator ~windowintersects~ */ int WindowIntersectsSelection( ListExpr args ) { AlgebraManager *algMgr = SecondoSystem::GetAlgebraManager(); ListExpr searchWindow = nl->Third(args), errorInfo = nl->OneElemList( nl->SymbolAtom( "ERRORS" ) ); if (nl->SymbolValue(searchWindow) == Rectangle<2>::BasicType() || algMgr->CheckKind(Kind::SPATIAL2D(), searchWindow, errorInfo)) return 0; else if (nl->SymbolValue(searchWindow) == Rectangle<3>::BasicType() || algMgr->CheckKind(Kind::SPATIAL3D(), searchWindow, errorInfo)) return 1; else if (nl->SymbolValue(searchWindow) == Rectangle<4>::BasicType() || algMgr->CheckKind(Kind::SPATIAL4D(), searchWindow, errorInfo)) return 2; else if (nl->SymbolValue(searchWindow) == Rectangle<8>::BasicType() || algMgr->CheckKind(Kind::SPATIAL8D(), searchWindow, errorInfo)) return 3; else if (nl->SymbolValue(searchWindow) == Rectangle<1>::BasicType() || algMgr->CheckKind(Kind::SPATIAL1D(), searchWindow, errorInfo)) return 4; return -1; /* should not happen */ } /* 5.1.3 Value mapping function of operator ~windowintersects~ */ #ifndef USE_PROGRESS // standard version template struct WindowIntersectsLocalInfo { Relation* relation; R_Tree* rtree; BBox *searchBox; bool first; }; template int WindowIntersects( Word* args, Word& result, int message, Word& local, Supplier s ) { WindowIntersectsLocalInfo *localInfo; switch (message) { case OPEN : { localInfo = new WindowIntersectsLocalInfo; localInfo->rtree = (R_Tree*)args[0].addr; localInfo->relation = (Relation*)args[1].addr; localInfo->first = true; localInfo->searchBox = new BBox ( (((StandardSpatialAttribute *)args[2].addr)-> BoundingBox()) ); assert(localInfo->rtree != 0); assert(localInfo->relation != 0); local.setAddr(localInfo); return 0; } case REQUEST : { localInfo = (WindowIntersectsLocalInfo*)local.addr; R_TreeLeafEntry e; if ( !localInfo->searchBox->IsDefined() ) { // search box is undefined -> no result! return CANCEL; } else { if(localInfo->first) { localInfo->first = false; if( localInfo->rtree->First( *localInfo->searchBox, e ) ) { Tuple *tuple = localInfo->relation->GetTuple(e.info); result.setAddr(tuple); return YIELD; } else return CANCEL; } else { if( localInfo->rtree->Next( e ) ) { Tuple *tuple = localInfo->relation->GetTuple(e.info); result.setAddr(tuple); return YIELD; } else return CANCEL; } } } case CLOSE : { if(local.addr) { localInfo = (WindowIntersectsLocalInfo*)local.addr; delete localInfo->searchBox; delete localInfo; local.setAddr(Address(0)); } return 0; } } return 0; } # else // progress version template class WindowIntersectsLocalInfo: public ProgressLocalInfo { public: Relation* relation; R_Tree* rtree; BBox *searchBox; bool first; int completeCalls; int completeReturned; }; template int WindowIntersects( Word* args, Word& result, int message, Word& local, Supplier s ) { WindowIntersectsLocalInfo *localInfo; localInfo = (WindowIntersectsLocalInfo*)local.addr; switch (message) { case OPEN : { //local info kept over many calls of OPEN! //useful for loopjoin if ( !localInfo ) // first time { localInfo = new WindowIntersectsLocalInfo; localInfo->completeCalls = 0; localInfo->completeReturned = 0; localInfo->sizesInitialized = false; localInfo->sizesChanged = false; localInfo->rtree = (R_Tree*)args[0].addr; localInfo->relation = (Relation*)args[1].addr; } localInfo->first = true; localInfo->searchBox = new BBox ( (((StandardSpatialAttribute *)args[2].addr)-> BoundingBox()) ); assert(localInfo->rtree != 0); assert(localInfo->relation != 0); local.setAddr(localInfo); return 0; } case REQUEST : { R_TreeLeafEntry e; if ( !localInfo->searchBox->IsDefined() ) { // search box is undefined -> no result! return CANCEL; } else { if(localInfo->first) { localInfo->first = false; if( localInfo->rtree->First( *localInfo->searchBox, e ) ) { Tuple *tuple = localInfo->relation->GetTuple(e.info,false); result.setAddr(tuple); localInfo->returned++; return YIELD; } else return CANCEL; } else { if( localInfo->rtree->Next( e ) ) { Tuple *tuple = localInfo->relation->GetTuple(e.info, false); result.setAddr(tuple); localInfo->returned++; return YIELD; } else return CANCEL; } } } case CLOSE : { if(local.addr) { delete localInfo->searchBox; localInfo->completeCalls++; localInfo->completeReturned += localInfo->returned; localInfo->returned = 0; //Do not delete localInfo data structure in CLOSE! //To be kept over several //calls for correct progress estimation when embedded in a loopjoin. //Is deleted at the end of the query in CLOSEPROGRESS. } return 0; } case CLOSEPROGRESS : { if(local.addr) { delete localInfo; local.setAddr(Address(0)); } return 0; } case REQUESTPROGRESS : { ProgressInfo *pRes; pRes = (ProgressInfo*) result.addr; //Experiments described in file Cost functions const double uSearch = 0.45; //milliseconds per search const double vResult = 0.092; //milliseconds per result tuple if (!localInfo) return CANCEL; else { localInfo->sizesChanged = false; if ( !localInfo->sizesInitialized ) { localInfo->returned = 0; localInfo->total = localInfo->relation->GetNoTuples(); localInfo->defaultValue = 50; localInfo->Size = 0; localInfo->SizeExt = 0; localInfo->noAttrs = nl->ListLength(nl->Second(nl->Second(qp->GetType(s)))); localInfo->attrSize = new double[localInfo->noAttrs]; localInfo->attrSizeExt = new double[localInfo->noAttrs]; for ( int i = 0; i < localInfo->noAttrs; i++) { localInfo->attrSize[i] = localInfo->relation->GetTotalSize(i) / (localInfo->total + 0.001); localInfo->attrSizeExt[i] = localInfo->relation->GetTotalExtSize(i) / (localInfo->total + 0.001); localInfo->Size += localInfo->attrSize[i]; localInfo->SizeExt += localInfo->attrSizeExt[i]; } localInfo->sizesInitialized = true; localInfo->sizesChanged = true; } pRes->CopySizes(localInfo); if ( localInfo->completeCalls > 0 ) //called in a loopjoin { pRes->Card = (double) localInfo->completeReturned / (double) localInfo->completeCalls; } else //single or first call { if (fabs(qp->GetSelectivity(s) - 0.1) < 0.000001) // default pRes->Card = (double) localInfo->defaultValue; else // annotated pRes->Card = localInfo->total * qp->GetSelectivity(s); if ((double) localInfo->returned > pRes->Card) // more tuples pRes->Card = (double) localInfo->returned; // than calculated if (!localInfo->searchBox) // rtree has been finished, but pRes->Card = pRes->Card * 1.1; // there are some tuples more (10%) if (pRes->Card > (double) localInfo->total) // more than all cannot be pRes->Card = (double) localInfo->total; } pRes->Time = uSearch + pRes->Card * vResult; pRes->Progress = (localInfo->returned + 1) / pRes->Card; return YIELD; } } } return 0; } #endif /* 5.1.4 Definition of value mapping vectors */ ValueMapping rtreewindowintersectsmap [] = { WindowIntersects<2>, WindowIntersects<3>, WindowIntersects<4>, WindowIntersects<8> }; /* 5.1.5 Specification of operator ~windowintersects~ */ const string windowintersectsSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" )" "( rtree(tuple ((x1 t1)...(xn tn))" " ti) x rel(tuple ((x1 t1)...(xn tn))) x T ->" " (stream (tuple ((x1 t1)...(xn tn))))\n" "For T= rect and ti in {rect} U SPATIALD, for" " d in {2, 3, 4, 8}" "_ _ windowintersects [ _ ]" "Uses the given rtree to find all tuples" " in the given relation with .xi intersects the " " argument value's bounding box." "query citiesInd cities windowintersects" " [r] consume; where citiesInd " "is e.g. created with 'let citiesInd = " "cities creatertree [pos]'" ") )"; /* 5.1.6 Definition of operator ~windowintersects~ */ Operator windowintersects ( "windowintersects", // name windowintersectsSpec, // specification 5, //number of overloaded functions rtreewindowintersectsmap, // value mapping WindowIntersectsSelection, // trivial selection function WindowIntersectsTypeMap // type mapping ); /* 7.2 Operator ~windowintersectsS~ 7.2.1 Type mapping function of operator ~windowintersectsS~ */ ListExpr WindowIntersectsSTypeMap(ListExpr args) { if( nl->IsEmpty(args) || nl->IsAtom(args) || nl->ListLength(args) != 2){ return listutils::typeError("Expects exactly 2 arguments."); } /* Split argument in two parts */ ListExpr rtreeDescription = nl->First(args); ListExpr searchWindow = nl->Second(args); // first must be an rtree if(!listutils::isRTreeDescription(rtreeDescription)){ return listutils::typeError("Expects 1st argument to be of type " "'rtree(,bool)'."); } // second a type with an MBR if(!( listutils::isSpatialType(searchWindow) || listutils::isRectangle(searchWindow))){ return listutils::typeError("Expects 2nd argument to be of a type of kind " "SPATIAL, SPATIAL3D, SPATIAL4D, SPATIAL8D; or of type 'rect', 'rect3', " "'rect4', or 'rect8'."); } // check for supported rtree dimensionality ListExpr rtreeKeyType = nl->Third(rtreeDescription); if(!( listutils::isSpatialType(rtreeKeyType) || listutils::isRectangle(rtreeKeyType))){ return listutils::typeError("Expects key type of the rtree passed as " "1st argument to to be of a type of kind " "SPATIAL, SPATIAL3D, SPATIAL4D, SPATIAL8D; or of type 'rect', 'rect3', " "'rect4', or 'rect8'."); } // Check whether key type and rtree dimension match if( !( (listutils::isKind(rtreeKeyType, Kind::SPATIAL2D()) && listutils::isSymbol(searchWindow, Rectangle<2>::BasicType())) || (listutils::isKind(rtreeKeyType, Kind::SPATIAL2D()) && listutils::isKind(searchWindow, Kind::SPATIAL2D())) || (listutils::isSymbol(searchWindow, Rectangle<2>::BasicType()) && listutils::isSymbol(rtreeKeyType, Rectangle<2>::BasicType())) ) && !( (listutils::isKind(rtreeKeyType, Kind::SPATIAL3D()) && listutils::isSymbol(searchWindow, Rectangle<3>::BasicType())) || (listutils::isKind(rtreeKeyType, Kind::SPATIAL3D()) && listutils::isKind(searchWindow, Kind::SPATIAL3D())) || (listutils::isSymbol(searchWindow, Rectangle<3>::BasicType()) && listutils::isSymbol(rtreeKeyType, Rectangle<3>::BasicType())) ) && !( (listutils::isKind(rtreeKeyType, Kind::SPATIAL4D()) && listutils::isSymbol(searchWindow, Rectangle<4>::BasicType())) || (listutils::isKind(rtreeKeyType, Kind::SPATIAL4D()) && listutils::isKind(searchWindow, Kind::SPATIAL4D())) || (listutils::isKind(searchWindow, Rectangle<4>::BasicType()) && listutils::isSymbol(rtreeKeyType, Rectangle<4>::BasicType())) ) && !( (listutils::isKind(rtreeKeyType, Kind::SPATIAL8D()) && listutils::isSymbol(searchWindow, Rectangle<8>::BasicType())) || (listutils::isKind(rtreeKeyType, Kind::SPATIAL8D()) && listutils::isKind(searchWindow, Kind::SPATIAL8D())) || (listutils::isKind(searchWindow, Rectangle<8>::BasicType()) && listutils::isSymbol(rtreeKeyType, Rectangle<8>::BasicType())) ) && !( (listutils::isKind(rtreeKeyType, Kind::SPATIAL1D()) && listutils::isSymbol(searchWindow, Rectangle<1>::BasicType())) || (listutils::isKind(rtreeKeyType, Kind::SPATIAL1D()) && listutils::isKind(searchWindow, Kind::SPATIAL1D())) || (listutils::isKind(searchWindow, Rectangle<1>::BasicType()) && listutils::isSymbol(rtreeKeyType, Rectangle<1>::BasicType())) ) ){ return listutils::typeError("Expects same dimensions for the rtree-type " "(1st argument) and for the key type (2nd argument)."); } // construct return type if( nl->BoolValue(nl->Fourth(rtreeDescription)) ) return nl->TwoElemList( nl->SymbolAtom(Symbol::STREAM()), nl->TwoElemList( nl->SymbolAtom(Tuple::BasicType()), nl->ThreeElemList( nl->TwoElemList( nl->SymbolAtom("Id"), nl->SymbolAtom(TupleIdentifier::BasicType())), nl->TwoElemList( nl->SymbolAtom("Low"), nl->SymbolAtom(CcInt::BasicType())), nl->TwoElemList( nl->SymbolAtom("High"), nl->SymbolAtom(CcInt::BasicType()))))); else return nl->TwoElemList( nl->SymbolAtom(Symbol::STREAM()), nl->TwoElemList( nl->SymbolAtom(Tuple::BasicType()), nl->OneElemList( nl->TwoElemList( nl->SymbolAtom("Id"), nl->SymbolAtom(TupleIdentifier::BasicType()))))); } /* 5.1.2 Selection function of operator ~windowintersectsS~ */ int WindowIntersectsSSelection( ListExpr args ) { AlgebraManager *algMgr = SecondoSystem::GetAlgebraManager(); ListExpr searchWindow = nl->Second(args), errorInfo = nl->OneElemList( nl->SymbolAtom( "ERRORS" ) ); bool doubleIndex = nl->BoolValue(nl->Fourth(nl->First(args))); if (nl->SymbolValue(searchWindow) == Rectangle<2>::BasicType() || algMgr->CheckKind(Kind::SPATIAL2D(), searchWindow, errorInfo)) return 0 + (!doubleIndex ? 0 : 5); else if (nl->SymbolValue(searchWindow) == Rectangle<3>::BasicType() || algMgr->CheckKind(Kind::SPATIAL3D(), searchWindow, errorInfo)) return 1 + (!doubleIndex ? 0 : 5); else if (nl->SymbolValue(searchWindow) == Rectangle<4>::BasicType() || algMgr->CheckKind(Kind::SPATIAL4D(), searchWindow, errorInfo)) return 2 + (!doubleIndex ? 0 : 5); else if (nl->SymbolValue(searchWindow) == Rectangle<8>::BasicType() || algMgr->CheckKind(Kind::SPATIAL8D(), searchWindow, errorInfo)) return 3 + (!doubleIndex ? 0 : 5); else if (nl->SymbolValue(searchWindow) == Rectangle<1>::BasicType() || algMgr->CheckKind(Kind::SPATIAL1D(), searchWindow, errorInfo)) return 4 + (!doubleIndex ? 0 : 5); return -1; /* should not happen */ } /* 5.1.3 Value mapping function of operator ~windowintersectsS~ */ #ifndef USE_PROGRESS // standard version template struct WindowIntersectsSLocalInfo { R_Tree* rtree; BBox *searchBox; TupleType *resultTupleType; bool first; }; template int WindowIntersectsSStandard( Word* args, Word& result, int message, Word& local, Supplier s ) { switch (message) { case OPEN : { WindowIntersectsSLocalInfo *localInfo = new WindowIntersectsSLocalInfo(); localInfo->rtree = (R_Tree*)args[0].addr; localInfo->first = true; localInfo->searchBox = new BBox ( (((StandardSpatialAttribute *)args[1].addr)-> BoundingBox()) ); localInfo->resultTupleType = new TupleType(nl->Second(GetTupleResultType(s))); local.setAddr(localInfo); return 0; } case REQUEST : { WindowIntersectsSLocalInfo *localInfo = (WindowIntersectsSLocalInfo*)local.addr; R_TreeLeafEntry e; if ( !localInfo->searchBox->IsDefined() ) { // search box is undefined -> no result! return CANCEL; } else { if(localInfo->first) { localInfo->first = false; if( localInfo->rtree->First( *localInfo->searchBox, e ) ) { Tuple *tuple = new Tuple( localInfo->resultTupleType ); tuple->PutAttribute(0, new TupleIdentifier(true, e.info)); result.setAddr(tuple); return YIELD; } else return CANCEL; } else { if( localInfo->rtree->Next( e ) ) { Tuple *tuple = new Tuple( localInfo->resultTupleType ); tuple->PutAttribute(0, new TupleIdentifier(true, e.info)); result.setAddr(tuple); return YIELD; } else return CANCEL; } } } case CLOSE : { if(local.addr) { WindowIntersectsSLocalInfo* localInfo = (WindowIntersectsSLocalInfo*)local.addr; delete localInfo->searchBox; localInfo->resultTupleType->DeleteIfAllowed(); delete localInfo; local.setAddr(Address(0)); } return 0; } } return 0; } template int WindowIntersectsSDoubleLayer( Word* args, Word& result, int message, Word& local, Supplier s ) { switch (message) { case OPEN : { WindowIntersectsSLocalInfo *localInfo = new WindowIntersectsSLocalInfo(); localInfo->rtree = (R_Tree*)args[0].addr; localInfo->first = true; localInfo->searchBox = new BBox ( (((StandardSpatialAttribute *)args[1].addr)-> BoundingBox()) ); localInfo->resultTupleType = new TupleType(nl->Second(GetTupleResultType(s))); local.setAddr(localInfo); return 0; } case REQUEST : { WindowIntersectsSLocalInfo *localInfo = (WindowIntersectsSLocalInfo*) local.addr; R_TreeLeafEntry e; if ( !localInfo->searchBox->IsDefined() ) { // search box is undefined -> no result! return CANCEL; } else { if(localInfo->first) { localInfo->first = false; if( localInfo->rtree->First( *localInfo->searchBox, e ) ) { Tuple *tuple = new Tuple( localInfo->resultTupleType ); tuple->PutAttribute( 0, new TupleIdentifier( true, e.info.tupleId ) ); tuple->PutAttribute( 1, new CcInt( true, e.info.low ) ); tuple->PutAttribute( 2, new CcInt( true, e.info.high ) ); result.setAddr(tuple); return YIELD; } else return CANCEL; } else { if( localInfo->rtree->Next( e ) ) { Tuple *tuple = new Tuple( localInfo->resultTupleType ); tuple->PutAttribute( 0, new TupleIdentifier( true, e.info.tupleId ) ); tuple->PutAttribute( 1, new CcInt( true, e.info.low ) ); tuple->PutAttribute( 2, new CcInt( true, e.info.high ) ); result.setAddr(tuple); return YIELD; } else return CANCEL; } } } case CLOSE : { if(local.addr) { WindowIntersectsSLocalInfo *localInfo = (WindowIntersectsSLocalInfo*) local.addr; delete localInfo->searchBox; localInfo->resultTupleType->DeleteIfAllowed(); delete localInfo; local.setAddr(Address(0)); } return 0; } } return 0; } # else // progress version template struct WindowIntersectsSLocalInfo: public ProgressLocalInfo { R_Tree* rtree; BBox *searchBox; TupleType *resultTupleType; bool first; int completeCalls; int completeReturned; }; template int WindowIntersectsSStandard( Word* args, Word& result, int message, Word& local, Supplier s ) { WindowIntersectsSLocalInfo *localInfo; localInfo = (WindowIntersectsSLocalInfo*)local.addr; switch (message) { case OPEN : { //local info kept over many calls of OPEN! //useful for loopjoin if ( !localInfo ) // first time { localInfo = new WindowIntersectsSLocalInfo; localInfo->completeCalls = 0; localInfo->completeReturned = 0; localInfo->sizesInitialized = false; localInfo->sizesChanged = false; localInfo->rtree = (R_Tree*)args[0].addr; localInfo->resultTupleType = new TupleType(nl->Second(GetTupleResultType(s))); } localInfo->first = true; localInfo->searchBox = new BBox ( (((StandardSpatialAttribute *)args[1].addr)-> BoundingBox()) ); local.setAddr(localInfo); return 0; } case REQUEST : { R_TreeLeafEntry e; if ( !localInfo->searchBox->IsDefined() ) { // search box is undefined -> no result! return CANCEL; } else { if(localInfo->first) { localInfo->first = false; if( localInfo->rtree->First( *localInfo->searchBox, e ) ) { Tuple *tuple = new Tuple( localInfo->resultTupleType ); tuple->PutAttribute(0, new TupleIdentifier(true, e.info)); result.setAddr(tuple); localInfo->returned++; return YIELD; } else return CANCEL; } else { if( localInfo->rtree->Next( e ) ) { Tuple *tuple = new Tuple( localInfo->resultTupleType ); tuple->PutAttribute(0, new TupleIdentifier(true, e.info)); result.setAddr(tuple); localInfo->returned++; return YIELD; } else return CANCEL; } } } case CLOSE : { if( localInfo ) { localInfo->completeCalls++; localInfo->completeReturned += localInfo->returned; localInfo->returned = 0; delete localInfo->searchBox; localInfo->searchBox = 0; //Do not delete localInfo data structure in CLOSE! //To be kept over several //calls for correct progress estimation when embedded in a loopjoin. //Is deleted at the end of the query in CLOSEPROGRESS. } return 0; } case CLOSEPROGRESS : { if( localInfo ) { localInfo->resultTupleType->DeleteIfAllowed(); delete localInfo; local.setAddr(Address(0)); } return 0; } case REQUESTPROGRESS : { ProgressInfo *pRes; pRes = (ProgressInfo*) result.addr; //Experiments described in file Cost functions const double uSearch = 0.45; //milliseconds per search const double vResult = 0.019; //milliseconds per result tuple if (!localInfo) return CANCEL; else { localInfo->sizesChanged = false; if ( !localInfo->sizesInitialized ) { localInfo->returned = 0; localInfo->defaultValue = 50; localInfo->Size = 16; localInfo->SizeExt = 16; localInfo->noAttrs = 1; localInfo->attrSize = new double[localInfo->noAttrs]; localInfo->attrSizeExt = new double[localInfo->noAttrs]; localInfo->attrSize[0] = 16; localInfo->attrSizeExt[0] = 16; localInfo->sizesInitialized = true; localInfo->sizesChanged = true; } pRes->CopySizes(localInfo); if ( localInfo->completeCalls > 0 ) //called in a loopjoin { pRes->Card = (double) localInfo->completeReturned / (double) localInfo->completeCalls; } else //single or first call { if (fabs(qp->GetSelectivity(s) - 0.1) < 0.000001) // default pRes->Card = (double) localInfo->defaultValue; else // annotated pRes->Card = localInfo->total * qp->GetSelectivity(s); if ((double) localInfo->returned > pRes->Card) // more tuples pRes->Card = (double) localInfo->returned; // than calculated if (!localInfo->searchBox) // rtree has been finished, but pRes->Card = pRes->Card * 1.1; // there are some tuples more (10%) if (pRes->Card > (double) localInfo->total) // more than all cannot be pRes->Card = (double) localInfo->total; } pRes->Time = uSearch + pRes->Card * vResult; pRes->Progress = (localInfo->returned + 1) / pRes->Card; return YIELD; } } } return 0; } template int WindowIntersectsSDoubleLayer( Word* args, Word& result, int message, Word& local, Supplier s ) { WindowIntersectsSLocalInfo *localInfo; localInfo = (WindowIntersectsSLocalInfo*)local.addr; switch (message) { case OPEN : { //local info kept over many calls of OPEN! //useful for loopjoin if ( !localInfo ) // first time { localInfo = new WindowIntersectsSLocalInfo; localInfo->completeCalls = 0; localInfo->completeReturned = 0; localInfo->sizesInitialized = false; localInfo->sizesChanged = false; localInfo->rtree = (R_Tree*)args[0].addr; localInfo->resultTupleType = new TupleType(nl->Second(GetTupleResultType(s))); } localInfo->first = true; localInfo->searchBox = new BBox ( (((StandardSpatialAttribute *)args[1].addr)-> BoundingBox()) ); local.setAddr(localInfo); return 0; } case REQUEST : { WindowIntersectsSLocalInfo *localInfo = (WindowIntersectsSLocalInfo*) local.addr; R_TreeLeafEntry e; if ( !localInfo->searchBox->IsDefined() ) { // search box is undefined -> no result! return CANCEL; } else { if(localInfo->first) { localInfo->first = false; if( localInfo->rtree->First( *localInfo->searchBox, e ) ) { Tuple *tuple = new Tuple( localInfo->resultTupleType ); tuple->PutAttribute( 0, new TupleIdentifier( true, e.info.tupleId ) ); tuple->PutAttribute( 1, new CcInt( true, e.info.low ) ); tuple->PutAttribute( 2, new CcInt( true, e.info.high ) ); result.setAddr(tuple); localInfo->returned++; return YIELD; } else return CANCEL; } else { if( localInfo->rtree->Next( e ) ) { Tuple *tuple = new Tuple( localInfo->resultTupleType ); tuple->PutAttribute( 0, new TupleIdentifier( true, e.info.tupleId ) ); tuple->PutAttribute( 1, new CcInt( true, e.info.low ) ); tuple->PutAttribute( 2, new CcInt( true, e.info.high ) ); result.setAddr(tuple); localInfo->returned++; return YIELD; } else return CANCEL; } } } case CLOSE : { if( localInfo ) { localInfo->completeCalls++; localInfo->completeReturned += localInfo->returned; localInfo->returned = 0; delete localInfo->searchBox; //Do not delete localInfo data structure in CLOSE! //To be kept over several //calls for correct progress estimation when embedded in a loopjoin. //Is deleted at the end of the query in CLOSEPROGRESS. } return 0; } case CLOSEPROGRESS : { if( localInfo ) { localInfo->resultTupleType->DeleteIfAllowed(); delete localInfo; local.setAddr(Address(0)); } return 0; } case REQUESTPROGRESS : { ProgressInfo *pRes; pRes = (ProgressInfo*) result.addr; //Experiments described in file Cost functions const double uSearch = 0.45; //milliseconds per search const double vResult = 0.02; //milliseconds per result tuple // vResult to be adjusted if (!localInfo) return CANCEL; else { localInfo->sizesChanged = false; if ( !localInfo->sizesInitialized ) { localInfo->returned = 0; localInfo->defaultValue = 50; localInfo->Size = 26; localInfo->SizeExt = 26; localInfo->noAttrs = 3; localInfo->attrSize = new double[localInfo->noAttrs]; localInfo->attrSizeExt = new double[localInfo->noAttrs]; localInfo->attrSize[0] = 16; localInfo->attrSizeExt[0] = 16; localInfo->attrSize[1] = 5; localInfo->attrSizeExt[1] = 5; localInfo->attrSize[2] = 5; localInfo->attrSizeExt[2] = 5; localInfo->sizesInitialized = true; localInfo->sizesChanged = true; } pRes->CopySizes(localInfo); if ( localInfo->completeCalls > 0 ) //called in a loopjoin { pRes->Card = (double) localInfo->completeReturned / (double) localInfo->completeCalls; } else //single or first call { if (fabs(qp->GetSelectivity(s) - 0.1) < 0.000001) // default pRes->Card = (double) localInfo->defaultValue; else // annotated pRes->Card = localInfo->total * qp->GetSelectivity(s); if ((double) localInfo->returned > pRes->Card) // more tuples pRes->Card = (double) localInfo->returned; // than calculated if (!localInfo->searchBox) // rtree has been finished, but pRes->Card = pRes->Card * 1.1; // there are some tuples more (10%) if (pRes->Card > (double) localInfo->total) // more than all cannot be pRes->Card = (double) localInfo->total; } pRes->Time = uSearch + pRes->Card * vResult; pRes->Progress = (localInfo->returned + 1) / pRes->Card; return YIELD; } } } return 0; } #endif /* 5.1.4 Definition of value mapping vectors */ ValueMapping rtreewindowintersectsSmap [] = { WindowIntersectsSStandard<2>, WindowIntersectsSStandard<3>, WindowIntersectsSStandard<4>, WindowIntersectsSStandard<8>, WindowIntersectsSStandard<1>, WindowIntersectsSDoubleLayer<2>, WindowIntersectsSDoubleLayer<3>, WindowIntersectsSDoubleLayer<4>, WindowIntersectsSDoubleLayer<8>, WindowIntersectsSDoubleLayer<1>}; /* 5.1.5 Specification of operator ~windowintersects~ */ const string windowintersectsSSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" )" "( (rtree (tuple((x1 t1)...(xn tn)) ti) x T ->" " (stream (tuple ((id tid))))" "For T=rect and ti in {rect} U SPATIALD, where " " d in {2, 3, 4, 8}. " "_ windowintersectsS [ _ ]" "Uses the given rtree to find the tuple " "identifiers of all entries, whose bounding box intersects " "with the argument value's bounding box." "query citiesInd windowintersects" " [r] consume; where citiesInd " "is e.g. created with 'let citiesInd = " "cities creatertree [pos]'" ") )"; /* 5.1.6 Definition of operator ~windowintersects~ */ Operator windowintersectsS ( "windowintersectsS", // name windowintersectsSSpec, // specification 10, //number of overloaded functions rtreewindowintersectsSmap, // value mapping WindowIntersectsSSelection, // trivial selection function WindowIntersectsSTypeMap // type mapping ); /* 7.2 Operator ~gettuples~ 7.2.1 Type mapping function of operator ~gettuples~ */ ListExpr GetTuplesTypeMap(ListExpr args) { // check for correct parameter list if(nl->IsEmpty(args) || nl->IsAtom(args) || nl->ListLength(args) != 2){ return listutils::typeError( "\nExpects exactly 2 arguments."); } // Split arguments into two parts ListExpr streamDescription = nl->First(args), relDescription = nl->Second(args); // Handle the stream part of arguments if(!listutils::isTupleStream(streamDescription)){ return listutils::typeError("Expects a valid tuplestream as 1st argument."); } // Handle the rel part of arguments if( !listutils::isRelDescription(relDescription) ){ return listutils::typeError("Expects a valid relation as 2nd argument."); } // Check for existence of a single tid-attribute int tidIndex = 0; string tidAttrName = ""; tidIndex = listutils::findType(nl->Second(nl->Second(streamDescription)), nl->SymbolAtom(TupleIdentifier::BasicType()), tidAttrName); if( tidIndex <= 0 ){ return listutils::typeError("Stream must contain an attribute of type " "'tid'."); } else if( tidIndex > 0 ){ int tidIndex2 = 0; string tidAttrName2 = ""; tidIndex2 = listutils::findType(nl->Second(nl->Second(streamDescription)), nl->SymbolAtom(TupleIdentifier::BasicType()), tidAttrName2, tidIndex+1); if (tidIndex2 != 0) { return listutils::typeError("Stream must contain at most one attribute" " of type 'tid'."); } } // remove tid-attribute from stream-attrlist set k; k.insert(tidAttrName); ListExpr tmp, tmpL; int noRemovedAttrs = 0; noRemovedAttrs = listutils::removeAttributes(nl->Second(nl->Second(streamDescription)), k, tmp, tmpL); if(noRemovedAttrs != 1){ return listutils::typeError("Stream must contain at most one attribute of " "type 'tid'."); } // append rel-attrlist to modified stream-attrlist ListExpr newAttrList = listutils::concat(tmp, nl->Second(nl->Second(relDescription))); // check whether result attrlist is valid if (!listutils::isAttrList(newAttrList)){ return listutils::typeError("Result after merging tuples is not a " "valid attribute list (Possible reasons: " "duplicate attribute names or an attribute " "type is not of kind DATA)."); } // return resulttype and APPEND tid-attr index in stream-attrlist return nl->ThreeElemList( nl->SymbolAtom(Symbol::APPEND()), nl->OneElemList( nl->IntAtom(tidIndex)), nl->TwoElemList( nl->SymbolAtom(Symbol::STREAM()), nl->TwoElemList( nl->SymbolAtom(Tuple::BasicType()), newAttrList))); } /* 5.1.3 Value mapping function of operator ~gettuples~ The template parameter ~TidIndexPos~ specifies the argument number, where the attribute index for the tid is stored within the stream argument's tuple type. For ~gettuples~, it is ~2~, for ~gettuples2~, it is ~3~. */ #ifndef USE_PROGRESS // standard version struct GetTuplesLocalInfo { Relation *relation; int tidIndex; TupleType *resultTupleType; }; template int GetTuples( Word* args, Word& result, int message, Word& local, Supplier s ) { GetTuplesLocalInfo *localInfo; static MessageCenter* msg = MessageCenter::GetInstance(); switch (message) { case OPEN : { assert( TidIndexPos == 2 || TidIndexPos == 3); int pos = TidIndexPos; if(TidIndexPos==3){ pos = qp->GetNoSons(s) -1; } qp->Open(args[0].addr); localInfo = new GetTuplesLocalInfo(); localInfo->relation = (Relation*)args[1].addr; localInfo->resultTupleType = new TupleType(nl->Second(GetTupleResultType(s))); localInfo->tidIndex = ((CcInt*)args[pos].addr)->GetIntval() - 1; // cerr << "GetTuples<" << TidIndexPos << ">(): localInfo->tidIndex = " // << localInfo->tidIndex << endl; local.setAddr(localInfo); return 0; } case REQUEST : { localInfo = (GetTuplesLocalInfo*)local.addr; Word wTuple; qp->Request(args[0].addr, wTuple); while( qp->Received(args[0].addr) ) { Tuple* sTuple = (Tuple*)wTuple.addr; Tuple* resultTuple = new Tuple( localInfo->resultTupleType ); Tuple* relTuple = localInfo->relation-> GetTuple(((TupleIdentifier *)sTuple-> GetAttribute(localInfo->tidIndex))->GetTid()); if(!relTuple){ NList msg_list(NList("simple") , NList("Warning: invalid tuple id")); msg->Send(msg_list); qp->Request(args[0].addr, wTuple); } else { int j = 0; // Copy the attributes from the stream tuple for( int i = 0; i < sTuple->GetNoAttributes(); i++ ) { if( i != localInfo->tidIndex ) resultTuple->CopyAttribute( i, sTuple, j++ ); } sTuple->DeleteIfAllowed(); for( int i = 0; i < relTuple->GetNoAttributes(); i++ ) { resultTuple->CopyAttribute( i, relTuple, j++ ); } relTuple->DeleteIfAllowed(); result.setAddr( resultTuple ); return YIELD; } } return CANCEL; } case CLOSE : { qp->Close(args[0].addr); if(local.addr) { localInfo = (GetTuplesLocalInfo*)local.addr; localInfo->resultTupleType->DeleteIfAllowed(); delete localInfo; local.setAddr(Address(0)); } return 0; } } return 0; } # else // progress version struct GetTuplesLocalInfo: public ProgressLocalInfo { Relation *relation; int tidIndex; TupleType *resultTupleType; }; template int GetTuples( Word* args, Word& result, int message, Word& local, Supplier s ) { GetTuplesLocalInfo *localInfo; localInfo = (GetTuplesLocalInfo*)local.addr; static MessageCenter* msg = MessageCenter::GetInstance(); switch (message) { case OPEN : { assert( TidIndexPos == 2 || TidIndexPos == 3); // 2 : gettuples // 3 : gettuples2 int pos = TidIndexPos; if(TidIndexPos==3){ pos = qp->GetNoSons(s) - 1; } qp->Open(args[0].addr); if ( !localInfo ) // first time { localInfo = new GetTuplesLocalInfo(); localInfo->relation = (Relation*)args[1].addr; localInfo->resultTupleType = new TupleType(nl->Second(GetTupleResultType(s))); localInfo->tidIndex = ((CcInt*)args[pos].addr)->GetIntval() - 1; local.setAddr(localInfo); } return 0; } case REQUEST : { Word wTuple; qp->Request(args[0].addr, wTuple); while( qp->Received(args[0].addr) ) { localInfo->read++; Tuple* sTuple = (Tuple*)wTuple.addr; Tuple* resultTuple = new Tuple( localInfo->resultTupleType ); Tuple* relTuple = localInfo->relation-> GetTuple(((TupleIdentifier *)sTuple-> GetAttribute(localInfo->tidIndex))->GetTid(),true); if(!relTuple){ ListExpr list = nl->TwoElemList( nl->SymbolAtom("simple"), nl->StringAtom("Warning: invalid tuple id")); msg->Send(nl,list); qp->Request(args[0].addr, wTuple); } else { int j = 0; // Copy the attributes from the stream tuple for( int i = 0; i < sTuple->GetNoAttributes(); i++ ) { if( i != localInfo->tidIndex ) resultTuple->CopyAttribute( i, sTuple, j++ ); } sTuple->DeleteIfAllowed(); for( int i = 0; i < relTuple->GetNoAttributes(); i++ ) { resultTuple->CopyAttribute( i, relTuple, j++ ); } relTuple->DeleteIfAllowed(); result.setAddr( resultTuple ); localInfo->returned++; return YIELD; } } return CANCEL; } case CLOSE : { qp->Close(args[0].addr); return 0; } case CLOSEPROGRESS : { if ( localInfo ) { localInfo->resultTupleType->DeleteIfAllowed(); delete localInfo; } local.setAddr(Address(0)); return 0; } case REQUESTPROGRESS : { ProgressInfo p1; ProgressInfo *pRes; pRes = (ProgressInfo*) result.addr; //Experiments described in file Cost functions const double uTuple = 0.061; //milliseconds per tuple const double vByte = 0.0000628; //milliseconds per byte if( !localInfo || !qp->RequestProgress(args[0].addr, &p1) ) { // ask stream argument return CANCEL; } localInfo->sizesChanged = (!localInfo->sizesInitialized || p1.sizesChanged); if ( localInfo->sizesChanged ){ localInfo->total = (int) p1.Card; localInfo->noAttrs = nl->ListLength(nl->Second(nl->Second(qp->GetType(s)))); if(!localInfo->sizesInitialized){ localInfo->attrSize = new double[localInfo->noAttrs]; localInfo->attrSizeExt = new double[localInfo->noAttrs]; } // ordering of attributes is: // attributes from first argument (without the one at tidIndex) // then relation attributes int no_stream_attrs = p1.noAttrs; int no_rel_attrs = localInfo->noAttrs - (no_stream_attrs - 1); // copy first part of stream attrs int j = 0; for (int i = 0; i < localInfo->tidIndex; i++) { localInfo->attrSize[j] = p1.attrSize[i]; localInfo->Size += p1.attrSize[i]; localInfo->attrSizeExt[j] = p1.attrSizeExt[i]; localInfo->SizeExt += p1.attrSizeExt[i]; j++; } // copy second part of stream attrs for (int i = localInfo->tidIndex+1; i < no_stream_attrs; i++) { localInfo->attrSize[j] = p1.attrSize[i]; localInfo->Size += p1.attrSize[i]; localInfo->attrSizeExt[j] = p1.attrSizeExt[i]; localInfo->SizeExt += p1.attrSizeExt[i]; j++; } // copy rel attrs for ( int i = 0; i < no_rel_attrs; i++) { localInfo->attrSize[j] = localInfo->relation->GetTotalSize(i) / (localInfo->total + 0.001); localInfo->attrSizeExt[j] = localInfo->relation->GetTotalExtSize(i) / (localInfo->total + 0.001); localInfo->Size += localInfo->attrSize[j]; localInfo->SizeExt += localInfo->attrSizeExt[j]; j++; } localInfo->sizesInitialized = true; } pRes->CopySizes(localInfo); pRes->Card = p1.Card; pRes->Time = p1.Time + p1.Card * (uTuple + vByte * localInfo->SizeExt); if ( p1.BTime < 0.1 && pipelinedProgress ) { //non-blocking, //use pipelining pRes->Progress = p1.Progress; } else { pRes->Progress = ((p1.Progress * p1.Time) + (localInfo->read / p1.Card) * (uTuple + vByte * localInfo->SizeExt)) / pRes->Time; } pRes->CopyBlocking(p1); return YIELD; } // case REQUESTPROGRESS } // switch return 0; } #endif /* 5.1.5 Specification of operator ~gettuples~ */ const string gettuplesSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" )" "( (stream (tuple ((id tid) (x1 t1)...(xn tn)))) x" " (rel (tuple ((y1 t1)...(yn tn)))) ->" " (stream (tuple ((x1 t1)...(xn tn) (y1 t1)...(yn tn))))" "" "_ _ gettuples" "Retrieves the tuples in the relation in the second " "argument given by the tuple id in first argument stream. " "The result tuple type is a concatenation of both types " "without the 'tid' attribute." "query citiesInd windowintersectsS[r] cities gettuples; " "where citiesInd is e.g. created with 'letidAttrName2t citiesInd = " "cities creatertree [pos]'" ") )"; /* 5.1.6 Definition of operator ~gettuples~ */ Operator gettuples ( "gettuples", // name gettuplesSpec, // specification GetTuples<2>, // value mapping Operator::SimpleSelect, // trivial selection function GetTuplesTypeMap // type mapping ); /* 7.2 Operator ~gettuples2~ 7.2.1 Type mapping function of operator ~gettuples2~ */ ListExpr renameAttr(ListExpr attr, const string& ext){ // expected format (attrname attrtype) return nl->TwoElemList( nl->SymbolAtom( nl->SymbolValue(nl->First(attr)) + ext), nl->Second(attr)); } ListExpr GetTuples2TypeMap(ListExpr args) { // check for correct parameter list if(!nl->HasLength(args,3) && !nl->HasLength(args,4)){ return listutils::typeError( "Expects 3 or 4 arguments."); } // Split arguments into three parts ListExpr streamDescription = nl->First(args); ListExpr relDescription = nl->Second(args); ListExpr tidArg = nl->Third(args); // Handle the stream part of arguments if(!Stream::checkType(streamDescription)){ return listutils::typeError("Expects a valid tuplestream as 1st argument."); } // Handle the rel part of arguments if( !Relation::checkType(relDescription)){ return listutils::typeError("Expects a valid relation as 2nd argument."); } // Check type of third argument (attribute name) if( nl->AtomType(tidArg) != SymbolType ){ return listutils::typeError("Expects attribute name as 3rd argument."); } if(nl->HasLength(args,4)){ if(nl->AtomType(nl->Fourth(args)) != SymbolType){ return listutils::typeError("required symbol for renaming"); } } string tidAttrName = nl->SymbolValue(tidArg); int tidIndex = 0; ListExpr attrType; tidIndex = listutils::findAttribute(nl->Second(nl->Second(streamDescription)), tidAttrName, attrType); if(!tidIndex){ return listutils::typeError("Attribute " + tidAttrName + " not found in tuple stream"); } if(!listutils::isSymbol(attrType, TupleIdentifier::BasicType())){ return listutils::typeError("Expects attribute to be of type 'tid'."); } // remove tid-attribute from stream-attrlist set k; k.insert(tidAttrName); ListExpr tmp, tmpL; int noRemovedAttrs = 0; noRemovedAttrs = listutils::removeAttributes(nl->Second(nl->Second(streamDescription)), k, tmp, tmpL); if(noRemovedAttrs != 1){ return listutils::typeError("Stream must contain at most one attribute of " "type 'tid'."); } // append rel-attrlist to modified stream-attrlist ListExpr relAttrList = nl->Second(nl->Second(relDescription)); // rename tuples from relation if requested if(nl->HasLength(args,4)){ string append = "_" + nl->SymbolValue(nl->Fourth(args)); ListExpr first = nl->First(relAttrList); ListExpr ren = nl->OneElemList( renameAttr(first,append)); ListExpr last = ren; relAttrList = nl->Rest(relAttrList); while(!nl->IsEmpty(relAttrList)){ last = nl->Append(last, renameAttr(nl->First(relAttrList),append)); relAttrList = nl->Rest(relAttrList); } relAttrList = ren; } ListExpr newAttrList = listutils::concat(tmp, relAttrList); // check whether result attrlist is valid if (!listutils::isAttrList(newAttrList)){ return listutils::typeError("Result after merging tuples is not a " "valid attribute list (Possible reasons: " "duplicate attribute names or an attribute " "type is not of kind DATA)."); } // return resulttype and APPEND tid-attr index in stream-attrlist return nl->ThreeElemList( nl->SymbolAtom(Symbol::APPEND()), nl->OneElemList( nl->IntAtom(tidIndex)), nl->TwoElemList( nl->SymbolAtom(Symbol::STREAM()), nl->TwoElemList( nl->SymbolAtom(Tuple::BasicType()), newAttrList))); } /* 5.1.3 Value mapping function of operator ~gettuples2~ The same as for ~gettuples~, but template parameter is ~3~. */ /* 5.1.5 Specification of operator ~gettuples2~ */ const string gettuples2Spec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" )" "( (stream (tuple ((id tid) (x1 t1)...(xn tn)))) x" " (rel (tuple ((y1 t1)...(yn tn)))) x id ->" " (stream (tuple ((x1 t1)...(xn tn) (y1 t1)...(yn tn))))" "" "_ _ gettuples2[ attr ] " "Retrieves the tuples in the relation 'rel' in the second " "argument given by the tuple id in argument 'attr' in the stream. " "(first argument). The result tuple type is a concatenation of both types " "without the 'id' attribute." "query citiesInd windowintersectsS[r] cities gettuples2[id]; " "where citiesInd is e.g. created with 'let citiesInd = " "cities creatertree [pos]'" ") )"; /* 5.1.6 Definition of operator ~gettuples2~ */ Operator gettuples2 ( "gettuples2", // name gettuples2Spec, // specification GetTuples<3>, // value mapping Operator::SimpleSelect, // trivial selection function GetTuples2TypeMap // type mapping ); /* 7.2 Operator ~gettuplesdbl~ 7.2.1 Type mapping function of operator ~gettuplesdbl~ */ ListExpr GetTuplesDblTypeMap(ListExpr args) { // check argument list length if(nl->IsEmpty(args) || nl->IsAtom(args) || !(nl->ListLength(args) == 3)){ return listutils::typeError("Expects exactly 3 arguments."); } // Split arguments into three parts ListExpr streamDescription = nl->First(args), relDescription = nl->Second(args), attrnameDescription = nl->Third(args); // Handle the stream part of arguments if ( !listutils::isTupleStream(streamDescription) ) { return listutils::typeError("Expects a valid tuplestream as 1st argument."); } // Handle the rel part of arguments if ( !listutils::isRelDescription(relDescription) ) { return listutils::typeError("Expects a valid relation as 2nd argument."); } ListExpr sTupleDescription = nl->Second(streamDescription), sAttrList = nl->Second(sTupleDescription), rTupleDescription = nl->Second(relDescription), rAttrList = nl->Second(rTupleDescription); // handle attribute name if(!listutils::isSymbol(attrnameDescription)){ return listutils::typeError("Expects the indexed attribute's name as 3rd " "argument."); } string attrName = nl->SymbolValue(attrnameDescription); ListExpr attrType; int attrIndex = listutils::findAttribute(rAttrList, attrName, attrType); if( attrIndex <= 0){ return listutils::typeError("Expects the attribute named by the 3rd " "argument being part of the relation passed as 2nd argument."); } // Find the attribute with type tid ListExpr first, rest, newAttrList=nl->TheEmptyList(), lastNewAttrList=nl->TheEmptyList(); int j, tidIndex = 0; string type; bool firstcall = true, dblIdxFirst = false; rest = sAttrList; j = 1; while (!nl->IsEmpty(rest)) { first = nl->First(rest); rest = nl->Rest(rest); type = nl->SymbolValue(nl->Second(first)); if (type == TupleIdentifier::BasicType()) { if( tidIndex != 0){ return listutils::typeError("Expects exactly one attribute of type " "'tid' in 1st argument."); } tidIndex = j; } else if( type == CcInt::BasicType() && tidIndex == j-1 ) { dblIdxFirst = true; } else if( type == CcInt::BasicType() && dblIdxFirst && tidIndex == j-2 ) { // dblIndex = true; } else { if (firstcall) { firstcall = false; newAttrList = nl->OneElemList(first); lastNewAttrList = newAttrList; } else lastNewAttrList = nl->Append(lastNewAttrList, first); } j++; } rest = rAttrList; while(!nl->IsEmpty(rest)) { first = nl->First(rest); rest = nl->Rest(rest); if (firstcall) { firstcall = false; newAttrList = nl->OneElemList(first); lastNewAttrList = newAttrList; } else lastNewAttrList = nl->Append(lastNewAttrList, first); } if( tidIndex == 0 ){ return listutils::typeError("Expects a stream with one and only one " "attribute of type tid as 1st argument."); } if( !listutils::isAttrList(newAttrList) ){ return listutils::typeError("Result after merging tuples is not a " "valid attribute list (Possible reasons: " "duplicate attribute names or an attribute " "type is not of kind DATA)."); } return nl->ThreeElemList( nl->SymbolAtom(Symbol::APPEND()), nl->TwoElemList( nl->IntAtom(attrIndex), nl->IntAtom(tidIndex)), nl->TwoElemList( nl->SymbolAtom(Symbol::STREAM()), nl->TwoElemList( nl->SymbolAtom(Tuple::BasicType()), newAttrList))); } /* 5.1.3 Value mapping functions of operator ~gettuplesdbl~ */ struct GetTuplesDblLocalInfo { Relation *relation; int attrIndex; int tidIndex; Tuple *lastTuple; vector< pair > intervals; TupleType *resultTupleType; }; int GetTuplesDbl( Word* args, Word& result, int message, Word& local, Supplier s ) { GetTuplesDblLocalInfo *localInfo; switch (message) { case OPEN : { qp->Open(args[0].addr); localInfo = new GetTuplesDblLocalInfo(); localInfo->relation = (Relation*)args[1].addr; localInfo->resultTupleType = new TupleType(nl->Second(GetTupleResultType(s))); localInfo->attrIndex = ((CcInt*)args[3].addr)->GetIntval() - 1; localInfo->tidIndex = ((CcInt*)args[4].addr)->GetIntval() - 1; localInfo->lastTuple = 0; local.setAddr(localInfo); return 0; } case REQUEST : { localInfo = (GetTuplesDblLocalInfo*)local.addr; Word wTuple; qp->Request(args[0].addr, wTuple); while( qp->Received(args[0].addr) ) { Tuple *sTuple = (Tuple*)wTuple.addr; if( localInfo->lastTuple == 0 ) { localInfo->lastTuple = sTuple; localInfo->intervals.push_back( make_pair( ((CcInt*)sTuple->GetAttribute( localInfo->tidIndex+1 ))-> GetIntval(), ((CcInt*)sTuple->GetAttribute( localInfo->tidIndex+2 ))-> GetIntval() ) ); } else if( sTuple->GetAttribute( localInfo->tidIndex )-> Compare( localInfo->lastTuple-> GetAttribute( localInfo->tidIndex ) ) == 0 ) { localInfo->intervals.push_back( make_pair( ((CcInt*)sTuple->GetAttribute( localInfo->tidIndex+1 ))-> GetIntval(), ((CcInt*)sTuple->GetAttribute( localInfo->tidIndex+2 ))-> GetIntval() ) ); sTuple->DeleteIfAllowed(); } else { Tuple *resultTuple = new Tuple( localInfo->resultTupleType ), *relTuple = localInfo->relation-> GetTuple( ((TupleIdentifier *)localInfo->lastTuple-> GetAttribute(localInfo->tidIndex))->GetTid(), localInfo->attrIndex, localInfo->intervals, false ); localInfo->intervals.clear(); localInfo->intervals.push_back( make_pair( ((CcInt*)sTuple->GetAttribute( localInfo->tidIndex+1 ))-> GetIntval(), ((CcInt*)sTuple->GetAttribute( localInfo->tidIndex+2 ))-> GetIntval() ) ); // Copy the attributes from the stream tuple int j = 0; for( int i = 0; i < localInfo->lastTuple->GetNoAttributes(); i++ ) { if( i < localInfo->tidIndex && // Strange thing: shoudn't it i > localInfo->tidIndex + 2 ) // be ( i<... || i>... ) ??? resultTuple->CopyAttribute( j++, localInfo->lastTuple, i ); } localInfo->lastTuple->DeleteIfAllowed(); localInfo->lastTuple = sTuple; for( int i = 0; i < relTuple->GetNoAttributes(); i++ ) resultTuple->CopyAttribute( j++, relTuple, i ); relTuple->DeleteIfAllowed(); result.setAddr( resultTuple ); return YIELD; } qp->Request(args[0].addr, wTuple); } if( localInfo->lastTuple != 0 ) { Tuple *resultTuple = new Tuple( localInfo->resultTupleType ), *relTuple = localInfo->relation-> GetTuple(((TupleIdentifier *)localInfo->lastTuple-> GetAttribute(localInfo->tidIndex))->GetTid(), localInfo->attrIndex, localInfo->intervals, false ); // Copy the attributes from the stream tuple int j = 0; for( int i = 0; i < localInfo->lastTuple->GetNoAttributes(); i++ ) { if( i < localInfo->tidIndex && i > localInfo->tidIndex + 2 ) resultTuple->CopyAttribute( j++, localInfo->lastTuple, i ); } localInfo->lastTuple->DeleteIfAllowed(); localInfo->lastTuple = 0; for( int i = 0; i < relTuple->GetNoAttributes(); i++ ) resultTuple->CopyAttribute( j++, relTuple, i ); relTuple->DeleteIfAllowed(); result.setAddr( resultTuple ); return YIELD; } else return CANCEL; } case CLOSE : { qp->Close(args[0].addr); if(local.addr) { localInfo = (GetTuplesDblLocalInfo*)local.addr; localInfo->resultTupleType->DeleteIfAllowed(); delete localInfo; local.setAddr(Address(0)); } return 0; } } return 0; } /* 5.1.5 Specification of operator ~gettuplesdbl~ */ const string GetTuplesDblSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" )" "( (stream (tuple ((id tid) (x1 t1)...(xn tn)))) x" " (rel (tuple ((y1 t1)...(yn tn)))) x yk ->" " (stream (tuple ((x1 t1)...(xn tn) (y1 t1)...(yn tn))))" "" "_ _ gettuplesdbl[ _ ]" "Retrieving tuples using double indexing. The tuples are " "retrieved from the relation in the second argument. " "The tuples to retrieve are given by a attribute of type 'tid' " "in first argument stream. " "The result tuple type is a concatenation of both types " "without the tid attribute. When the tid is followed by two int " "attributes in the first stream argument, these integers will be " "used to restrict the Flob belonging to the attribute indicated " "by its name in the 3rd argument to a specific interval." "query citiesInd windowintersectsS[r] cities gettuplesdbl; " "where citiesInd is e.g. created with 'let citiesInd = " "cities creatertree [pos]'" ") )"; /* 5.1.6 Definition of operator ~gettuplesdbl~ */ Operator gettuplesdbl ( "gettuplesdbl", // name GetTuplesDblSpec, // specification GetTuplesDbl, // value mapping Operator::SimpleSelect, // selection function GetTuplesDblTypeMap // type mapping ); /* 5.2 Operator ~creatertree\_bulkload~ This operator will create a new r-tree from the scratch, applying a simple bulkload mechanism. The input relation/stream is read and partition them into $p =\lceil \frac{N}{c} \rceil$ leaf pages. Then start aggregating the leafnodes into $p :=\lceil \frac{p}{c} \rceil$ internal nodes until only a single node, the root, remains. Problems: There may be many nodes to be handled, so we need to store the current working set of nodes and within a persistent buffer. Sorting is not implemented within this algorithm. The input should already be sorted with respect to the center or lower left corner of the input bounding boxes, e.g. using a Z-order. You can apply other kinds of orderings to take some influence on the overlapping within the r-tree. */ /* 5.2. TypeMapping for Operator ~creatertree\_bulkload~ Signature is ---- creatertree_bulkload: stream ---- */ ListExpr CreateRTreeBulkLoadTypeMap(ListExpr args) { // check number of parameters int len = nl->ListLength(args); if( (len != 2) && (len!=3) ){ return listutils::typeError("Expecting exactly 2 or 3 arguments."); } // split to parameters ListExpr tupleStream = nl->First(args), attrNameLE = nl->Second(args); // check stream if(!listutils::isTupleStream(tupleStream)){ return listutils::typeError("Expecting a tuplestream as 1st argument."); } // check key attribute name if(!listutils::isSymbol(attrNameLE)){ return listutils::typeError("Expecting an attribute name as 2nd argument."); } string attrName = nl->SymbolValue(attrNameLE); // check if key attribute is from stream ListExpr attrList = nl->Second(nl->Second(tupleStream)); ListExpr attrType; int attrIndex = listutils::findAttribute(attrList, attrName, attrType); if(attrIndex <= 0){ return listutils::typeError("Expecting the attribute (2nd argument) being " "part of the tuplestream (1st argument)."); } // check for type of key attribute if( !(listutils::isSpatialType(attrType)||listutils::isRectangle(attrType))){ return listutils::typeError("Expecting the key attribute (2nd argument) " "being of kind SPATIAL2D, SPATIAL3D, Spatial4D or SPATIAL8D, of of " "type rect, rect3, rect4, or rect8."); } string rtreetype; if( listutils::isKind(attrType, Kind::SPATIAL2D()) || listutils::isSymbol(attrType, Rectangle<2>::BasicType())){ rtreetype = RTree2TID::BasicType(); }else if( listutils::isKind(attrType, Kind::SPATIAL3D()) || listutils::isSymbol(attrType, Rectangle<3>::BasicType())){ rtreetype = RTree3TID::BasicType(); }else if( listutils::isKind(attrType, Kind::SPATIAL4D()) || listutils::isSymbol(attrType, Rectangle<4>::BasicType())){ rtreetype = RTree4TID::BasicType(); }else if( listutils::isKind(attrType, Kind::SPATIAL8D()) || listutils::isSymbol(attrType, Rectangle<8>::BasicType())){ rtreetype = RTree8TID::BasicType(); }else if( listutils::isKind(attrType, Kind::SPATIAL1D()) || listutils::isSymbol(attrType, Rectangle<1>::BasicType())){ rtreetype = RTree1TID::BasicType(); }else{ return listutils::typeError("Unsupported key type."); } /* Now we have two possibilities: - multi-entry indexing, or - double indexing For multi-entry indexing, one and only one of the attributes must be a tuple identifier. In the latter, together with a tuple identifier, the last two attributes must be of integer type (~int~). In the first case, a standard R-Tree is created possibly containing several entries to the same tuple identifier, and in the latter, a double index R-Tree is created using as low and high parameters these two last integer numbers. */ ListExpr first, rest, newAttrList=nl->TheEmptyList(), lastNewAttrList=nl->TheEmptyList(); int tidIndex = 0; bool firstcall = true, doubleIndex = false; int nAttrs = nl->ListLength( attrList ); rest = attrList; int j = 1; while (!nl->IsEmpty(rest)) { first = nl->First(rest); rest = nl->Rest(rest); ListExpr type = nl->Second(first); if (TupleIdentifier::checkType(type)) { if( tidIndex != 0 && (len != 3)){ return listutils::typeError("Expecting exactly one attribute of type " "'tid' in the 1st argument."); } tidIndex = j; } else if( j == nAttrs - 1 && CcInt::checkType(type) && CcInt::checkType( nl->Second(nl->First(rest))) ) { // the last two attributes are integers doubleIndex = true; } else { if (firstcall) { firstcall = false; newAttrList = nl->OneElemList(first); lastNewAttrList = newAttrList; } else { lastNewAttrList = nl->Append(lastNewAttrList, first); } } j++; } if(len==3){ // ignore the tid index computed before ListExpr tidName = nl->Third(args); if(!listutils::isSymbol(tidName)){ return listutils::typeError("third argument " "must be an attribute name "); } string tidn = nl->SymbolValue(tidName); ListExpr tidType; tidIndex = listutils::findAttribute(attrList, tidn,tidType); if(tidIndex==0){ return listutils::typeError("Attribute " + tidn + " not present in tuple. "); } if(!TupleIdentifier::checkType(tidType)){ return listutils::typeError("Attribute " + tidn + " is not a tuple identifier "); } } else if( tidIndex == 0 ){ return listutils::typeError("Expecting exactly one attribute of type " "'tid' in the 1st argument."); } ListExpr res = nl->ThreeElemList( nl->SymbolAtom(Symbol::APPEND()), nl->TwoElemList( nl->IntAtom(attrIndex), nl->IntAtom(tidIndex)), nl->FourElemList( nl->SymbolAtom(rtreetype), nl->TwoElemList( nl->SymbolAtom(Tuple::BasicType()), newAttrList), attrType, nl->BoolAtom(doubleIndex))); return res; } /* 5.2. Value Mapping for Operator ~creatertree\_bulkload~ */ template int CreateRTreeBulkLoadStreamSpatial( Word* args, Word& result, int message, Word& local, Supplier s ) { // Step 0 - Initialization int argOffset = qp->GetNoSons(s)==4?0:1; Word wTuple; R_Tree *rtree = (R_Tree*)qp->ResultStorage(s).addr; result.setAddr( rtree ); int attrIndex = ((CcInt*)args[2+argOffset].addr)->GetIntval() - 1, tidIndex = ((CcInt*)args[3+argOffset].addr)->GetIntval() - 1; // Get a reference to the message center static MessageCenter* msg = MessageCenter::GetInstance(); int count = 0; // counter for progress indicator bool BulkLoadInitialized = rtree->InitializeBulkLoad(); assert(BulkLoadInitialized); qp->Open(args[0].addr); qp->Request(args[0].addr, wTuple); while (qp->Received(args[0].addr)) { if ((count++ % 10000) == 0) { // build a two elem list (simple count) ListExpr list = listutils::simpleMessage(count); // send the message, the message center will call // the registered handlers. Normally the client applications // will register them. msg->Send(nl,list); } Tuple* tuple = (Tuple*)wTuple.addr; if( ((StandardSpatialAttribute*)tuple-> GetAttribute(attrIndex))->IsDefined() && ((TupleIdentifier *)tuple->GetAttribute(tidIndex))-> IsDefined() ) { BBox box = ((StandardSpatialAttribute*)tuple-> GetAttribute(attrIndex))->BoundingBox(); /////only for Greece knn algorithm//// // if(dim == 3){ // double min[3]; // double max[3]; // for(int i = 0;i < 3;i++){ // min[i] = box.MinD(i); // max[i] = box.MaxD(i); // } // min[2] = min[2]*864000; // max[2] = max[2]*864000; // box.Set(true,min,max); // } ////////// if(box.IsDefined()){ R_TreeLeafEntry e( box, ((TupleIdentifier *)tuple-> GetAttribute(tidIndex))->GetTid() ); rtree->InsertBulkLoad(e); } } tuple->DeleteIfAllowed(); qp->Request(args[0].addr, wTuple); } qp->Close(args[0].addr); int FinalizedBulkLoad = rtree->FinalizeBulkLoad(); assert( FinalizedBulkLoad ); // build a two elem list (simple count) // send the message, the message center will call // the registered handlers. Normally the client applications // will register them. msg->Send(nl,listutils::simpleMessage(count)); return 0; } // VM for double layer indexing template int CreateRTreeBulkLoadStreamL2Spatial(Word* args, Word& result, int message, Word& local, Supplier s) { int argsOffset = qp->GetNoSons(s)==4?0:1; Word wTuple; R_Tree *rtree = (R_Tree*)qp->ResultStorage(s).addr; result.setAddr( rtree ); int attrIndex = ((CcInt*)args[2+argsOffset].addr)->GetIntval() - 1, tidIndex = ((CcInt*)args[3+argsOffset].addr)->GetIntval() - 1; // Get a reference to the message center static MessageCenter* msg = MessageCenter::GetInstance(); int count = 0; // counter for progress indicator bool BulkLoadInitialized = rtree->InitializeBulkLoad(); assert(BulkLoadInitialized); qp->Open(args[0].addr); qp->Request(args[0].addr, wTuple); while (qp->Received(args[0].addr)) { if ((count++ % 10000) == 0) { // send the message, the message center will call // the registered handlers. Normally the client applications // will register them. msg->Send(nl, listutils::simpleMessage(count)); } Tuple* tuple = (Tuple*)wTuple.addr; if( ((StandardSpatialAttribute*)tuple-> GetAttribute(attrIndex))->IsDefined() && ((TupleIdentifier *)tuple->GetAttribute(tidIndex))-> IsDefined() && ((CcInt*)tuple->GetAttribute(tuple->GetNoAttributes()-2))-> IsDefined() && ((CcInt*)tuple->GetAttribute(tuple->GetNoAttributes()-1))-> IsDefined() ) { BBox box = ((StandardSpatialAttribute*)tuple-> GetAttribute(attrIndex))->BoundingBox(); if (box.IsDefined()) { R_TreeLeafEntry e(box, TwoLayerLeafInfo( ((TupleIdentifier *)tuple-> GetAttribute(tidIndex))->GetTid(), ((CcInt*)tuple-> GetAttribute(tuple->GetNoAttributes()-2))->GetIntval(), ((CcInt*)tuple-> GetAttribute(tuple->GetNoAttributes()-1))->GetIntval())); rtree->InsertBulkLoad(e); } } tuple->DeleteIfAllowed(); qp->Request(args[0].addr, wTuple); } qp->Close(args[0].addr); int FinalizedBulkLoad = rtree->FinalizeBulkLoad(); assert( FinalizedBulkLoad ); // send the message, the message center will call // the registered handlers. Normally the client applications // will register them. msg->Send(nl, listutils::simpleMessage(count)); return 0; } template int CreateRTreeBulkLoadStreamRect( Word* args, Word& result, int message, Word& local, Supplier s ) { int argOffset = qp->GetNoSons(s)==4?0:1; Word wTuple; R_Tree *rtree = (R_Tree*)qp->ResultStorage(s).addr; result.setAddr( rtree ); int attrIndex = ((CcInt*)args[2+argOffset].addr)->GetIntval() - 1, tidIndex = ((CcInt*)args[3+argOffset].addr)->GetIntval() - 1; // Get a reference to the message center static MessageCenter* msg = MessageCenter::GetInstance(); int count = 0; // counter for progress indicator bool BulkLoadInitialized = rtree->InitializeBulkLoad(); assert(BulkLoadInitialized); qp->Open(args[0].addr); qp->Request(args[0].addr, wTuple); while (qp->Received(args[0].addr)) { if ((count++ % 10000) == 0) { // send the message, the message center will call // the registered handlers. Normally the client applications // will register them. msg->Send(nl, listutils::simpleMessage(count)); } Tuple* tuple = (Tuple*)wTuple.addr; BBox *box = (BBox*)tuple->GetAttribute(attrIndex); if( box->IsDefined() && ((TupleIdentifier *)tuple->GetAttribute(tidIndex))->IsDefined() ) { R_TreeLeafEntry e( *box, ((TupleIdentifier *)tuple-> GetAttribute(tidIndex))->GetTid() ); rtree->InsertBulkLoad(e); } tuple->DeleteIfAllowed(); qp->Request(args[0].addr, wTuple); } qp->Close(args[0].addr); int FinalizedBulkLoad = rtree->FinalizeBulkLoad(); assert( FinalizedBulkLoad ); // send the message, the message center will call // the registered handlers. Normally the client applications // will register them. msg->Send(nl, listutils::simpleMessage(count)); return 0; } // VM for double layer indexing template int CreateRTreeBulkLoadStreamL2Rect(Word* args, Word& result, int message, Word& local, Supplier s) { int argOffset = qp->GetNoSons(s)==4?0:1; Word wTuple; R_Tree *rtree = (R_Tree*)qp->ResultStorage(s).addr; result.setAddr( rtree ); int attrIndex = ((CcInt*)args[2+argOffset].addr)->GetIntval() - 1, tidIndex = ((CcInt*)args[3+argOffset].addr)->GetIntval() - 1; // Get a reference to the message center static MessageCenter* msg = MessageCenter::GetInstance(); int count = 0; // counter for progress indicator bool BulkLoadInitialized = rtree->InitializeBulkLoad(); assert(BulkLoadInitialized); qp->Open(args[0].addr); qp->Request(args[0].addr, wTuple); while (qp->Received(args[0].addr)) { if ((count++ % 10000) == 0) { // send the message, the message center will call // the registered handlers. Normally the client applications // will register them. msg->Send(nl, listutils::simpleMessage(count)); } Tuple* tuple = (Tuple*)wTuple.addr; if( ((StandardSpatialAttribute*)tuple-> GetAttribute(attrIndex))->IsDefined() && ((TupleIdentifier *)tuple->GetAttribute(tidIndex))-> IsDefined() && ((CcInt*)tuple->GetAttribute(tuple->GetNoAttributes()-2))-> IsDefined() && ((CcInt*)tuple->GetAttribute(tuple->GetNoAttributes()-1))-> IsDefined() ) { BBox *box = (BBox*)tuple->GetAttribute(attrIndex); if( box->IsDefined() ) { R_TreeLeafEntry e( *box, TwoLayerLeafInfo( ((TupleIdentifier *)tuple-> GetAttribute(tidIndex))->GetTid(), ((CcInt*)tuple->GetAttribute( tuple->GetNoAttributes()-2))->GetIntval(), ((CcInt*)tuple->GetAttribute( tuple->GetNoAttributes()-1))->GetIntval() ) ); rtree->InsertBulkLoad(e); } } tuple->DeleteIfAllowed(); qp->Request(args[0].addr, wTuple); } qp->Close(args[0].addr); int FinalizedBulkLoad = rtree->FinalizeBulkLoad(); assert( FinalizedBulkLoad ); // send the message, the message center will call // the registered handlers. Normally the client applications // will register them. msg->Send(nl, listutils::simpleMessage(count)); return 0; } /* 5.2. Selection Function for Operator ~creatertree\_bulkload~ */ int CreateRTreeBulkLoadSelect (ListExpr args) { ListExpr relDescription = nl->First(args), attrNameLE = nl->Second(args), tupleDescription = nl->Second(relDescription), attrList = nl->Second(tupleDescription); string attrName = nl->SymbolValue(attrNameLE); ListExpr attrType; FindAttribute(attrList, attrName, attrType); AlgebraManager* algMgr = SecondoSystem::GetAlgebraManager(); ListExpr errorInfo = nl->OneElemList( nl->SymbolAtom( "ERRORS" ) ); int result; if ( algMgr->CheckKind(Kind::SPATIAL2D(), attrType, errorInfo) ) result = 0; else if ( algMgr->CheckKind(Kind::SPATIAL3D(), attrType, errorInfo) ) result = 1; else if ( algMgr->CheckKind(Kind::SPATIAL4D(), attrType, errorInfo) ) result = 2; else if ( algMgr->CheckKind(Kind::SPATIAL8D(), attrType, errorInfo) ) result = 3; else if ( algMgr->CheckKind(Kind::SPATIAL1D(), attrType, errorInfo) ) result = 4; else if( nl->SymbolValue(attrType) == Rectangle<2>::BasicType() ) result = 5; else if( nl->SymbolValue(attrType) == Rectangle<3>::BasicType() ) result = 6; else if( nl->SymbolValue(attrType) == Rectangle<4>::BasicType() ) result = 7; else if( nl->SymbolValue(attrType) == Rectangle<8>::BasicType() ) result = 8; else if( nl->SymbolValue(attrType) == Rectangle<1>::BasicType() ) result = 9; else return -1; /* should not happen */ if( nl->SymbolValue(nl->First(relDescription)) == Symbol::STREAM()) { ListExpr first, rest = attrList; while (!nl->IsEmpty(rest)) { first = nl->First(rest); rest = nl->Rest(rest); } if( nl->IsEqual( nl->Second( first ), CcInt::BasicType() ) ) // Double indexing return result + 10; else // Multi-entry indexing return result + 0; } return -1; } ValueMapping CreateRTreeBulkLoad [] = { CreateRTreeBulkLoadStreamSpatial<2>, CreateRTreeBulkLoadStreamSpatial<3>, CreateRTreeBulkLoadStreamSpatial<4>, CreateRTreeBulkLoadStreamSpatial<8>, CreateRTreeBulkLoadStreamSpatial<1>, CreateRTreeBulkLoadStreamRect<2>, CreateRTreeBulkLoadStreamRect<3>, CreateRTreeBulkLoadStreamRect<4>, CreateRTreeBulkLoadStreamRect<8>, CreateRTreeBulkLoadStreamRect<1>, CreateRTreeBulkLoadStreamL2Spatial<2>, CreateRTreeBulkLoadStreamL2Spatial<3>, CreateRTreeBulkLoadStreamL2Spatial<4>, CreateRTreeBulkLoadStreamL2Spatial<8>, CreateRTreeBulkLoadStreamL2Spatial<1>, CreateRTreeBulkLoadStreamL2Rect<2>, CreateRTreeBulkLoadStreamL2Rect<3>, CreateRTreeBulkLoadStreamL2Rect<4>, CreateRTreeBulkLoadStreamL2Rect<8>, CreateRTreeBulkLoadStreamL2Rect<1>}; /* 5.2. Specification for Operator ~creatertree\_bulkload~ */ const string CreateRTreeBulkLoadSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" " "\"Example\" \"Comment\" ) " "((stream (tuple (x1 t1)...(xn tn) (id tid))) xi)" " -> (rtree (tuple ((x1 t1)...(xn tn))) ti false)\n" "((stream (tuple (x1 t1)...(xn tn) " "(id tid)(low int)(high int))) xi)" " -> (rtree (tuple ((x1 t1)...(xn tn))) ti true)" "bulkloadrtree [ _ ]" "Creates an rtree applying bulk loading. This means, " "the operator expects the input stream of tuples to be ordered " "in some meaningful way in order to reduce overlapping of " "bounding boxes (e.g. a Z-ordering on the bounding boxes). " "The R-Tree is created bottom up by gouping as many entries as " "possible into the leaf nodes and then creating the higher levels. " "The key type ti must be of kind SPATIAL2D, SPATIAL3D, SPATIAL4D " "or Spatial8D, or of type rect, rect2, rect3, rect4 or rect8." "let myrtree = Kreis feed projectextend[ ; TID: tupleid(.), " "MBR: bbox(.Gebiet)] sortby[MBR asc] bulkloadrtree[MBR]" "" ") )"; /* 5.2. Definition of Operator ~creatertree\_bulkload~ */ Operator bulkloadrtree( "bulkloadrtree", // name CreateRTreeBulkLoadSpec, // specification 16, CreateRTreeBulkLoad, // value mapping CreateRTreeBulkLoadSelect, // selection function CreateRTreeBulkLoadTypeMap // type mapping ); /* 5.9 Inquiry Operators ~treeheight~, ~no\_nodes~, ~no\_entries~, ~bbox~, ~getRootNode~ This operators can be used to inquire some basic R-tree statistics. */ /* 5.9.1 Type Mapping Function for ~treeheight~, ~no\_nodes~, ~no\_entries~, ~bbox~, ~getRootNode~ */ ListExpr RTree2IntTypeMap(ListExpr args) { if(nl->IsEmpty(args) || nl->IsAtom(args) || nl->ListLength(args) != 1){ return listutils::typeError("Expected exactly 1 argument."); } ListExpr rtreeDescription = nl->First(args); if( !listutils::isRTreeDescription(rtreeDescription ) ){ return listutils::typeError("Expected rtree as 1st argument."); } return nl->SymbolAtom(CcInt::BasicType()); } /* 5.9.1 Type Mapping Function for ~getFileInfo~ */ ListExpr RTree2TextTypeMap(ListExpr args) { if(nl->IsEmpty(args) || nl->IsAtom(args) || nl->ListLength(args) != 1){ return listutils::typeError("Expected exactly 1 argument."); }; ListExpr rtreeDescription = nl->First(args); if( !listutils::isRTreeDescription(rtreeDescription ) ){ return listutils::typeError("Expected rtree as 1st argument."); } return nl->SymbolAtom(FText::BasicType()); } /* 5.9.1 Type Mapping Function for ~bbox~ */ ListExpr RTree2RectTypeMap(ListExpr args) { if(nl->IsEmpty(args) || nl->IsAtom(args) || nl->ListLength(args) != 1){ return listutils::typeError("Expected exactly 1 argument."); }; ListExpr rtreeDescription = nl->First(args); if( !listutils::isRTreeDescription(rtreeDescription ) ){ return listutils::typeError("Expected rtree as 1st argument."); } ListExpr rtreeSymbol = nl->First(rtreeDescription); if(nl->SymbolValue(rtreeSymbol) == RTree2TID::BasicType()) return nl->SymbolAtom(Rectangle<2>::BasicType()); else if(nl->SymbolValue(rtreeSymbol) == RTree3TID::BasicType()) return nl->SymbolAtom(Rectangle<3>::BasicType()); else if(nl->SymbolValue(rtreeSymbol) == RTree4TID::BasicType()) return nl->SymbolAtom(Rectangle<4>::BasicType()); else if(nl->SymbolValue(rtreeSymbol) == RTree8TID::BasicType()) return nl->SymbolAtom(Rectangle<8>::BasicType()); else return listutils::typeError("Unsupported rtee-type."); } /* 5.9.2 Value Mapping Functions for ~treeheight~, ~no\_nodes~, ~no\_entries~, ~bbox~, ~getRootNode~ */ template int RTreeTreeHeightVM( Word* args, Word& result, int message, Word& local, Supplier s ) { R_Tree *rtree = (R_Tree*) args[0].addr; result = qp->ResultStorage( s ); CcInt *res = (CcInt*) result.addr; res->Set( true, rtree->Height() ); return 0; } template int RTreeNoOfNodesVM( Word* args, Word& result, int message, Word& local, Supplier s ) { R_Tree *rtree = (R_Tree*) args[0].addr; result = qp->ResultStorage( s ); CcInt *res = (CcInt*) result.addr; res->Set( true, rtree->NodeCount() ); return 0; } template int RTreeNoOfEntriesVM( Word* args, Word& result, int message, Word& local, Supplier s ) { R_Tree *rtree = (R_Tree*) args[0].addr; result = qp->ResultStorage( s ); CcInt *res = (CcInt*) result.addr; res->Set( true, rtree->EntryCount() ); return 0; } template int RTreeBboxVM( Word* args, Word& result, int message, Word& local, Supplier s ) { R_Tree *rtree = (R_Tree*) args[0].addr; result = qp->ResultStorage( s ); Rectangle *res = (Rectangle *) result.addr; *res = rtree->BoundingBox(); return 0; } template int RTreeGetRootNodeVM( Word* args, Word& result, int message, Word& local, Supplier s ) { R_Tree *rtree = (R_Tree*) args[0].addr; result = qp->ResultStorage( s ); CcInt *res = (CcInt*) result.addr; res->Set( true, rtree->RootRecordId() ); return 0; } /* 5.9.3 Selection Function for ~treeheight~, ~no\_nodes~, ~no\_entries~, ~bbox~, ~getRootNode~ */ int RTreeInquirySelect (ListExpr args) { int result = -100; ListExpr rtreeDescription = nl->First(args); ListExpr rtreeSymbol = nl->First(rtreeDescription), rtreeTwoLayer = nl->Fourth(rtreeDescription); if(nl->SymbolValue(rtreeSymbol) == RTree2TID::BasicType()) result = 0; else if(nl->SymbolValue(rtreeSymbol) == RTree3TID::BasicType()) result = 1; else if(nl->SymbolValue(rtreeSymbol) == RTree4TID::BasicType()) result = 2; else if(nl->SymbolValue(rtreeSymbol) == RTree8TID::BasicType()) result = 3; if( nl->BoolValue(rtreeTwoLayer) == true ) result += 4; return result; } /* 5.9.3 Value Mapping Arrays for ~treeheight~, ~no\_nodes~, ~no\_entries~, ~bbox~, ~getRootNode~ */ ValueMapping RTreeTreeHeight [] = { RTreeTreeHeightVM<2, TupleId>, // 0 RTreeTreeHeightVM<3, TupleId>, // 1 RTreeTreeHeightVM<4, TupleId>, // 2 RTreeTreeHeightVM<8, TupleId>, // 3 RTreeTreeHeightVM<2, TwoLayerLeafInfo>, // 4 RTreeTreeHeightVM<3, TwoLayerLeafInfo>, // 5 RTreeTreeHeightVM<4, TwoLayerLeafInfo>, // 6 RTreeTreeHeightVM<8, TwoLayerLeafInfo> // 7 }; ValueMapping RTreeNoOfEntries [] = { RTreeNoOfEntriesVM<2, TupleId>, // 0 RTreeNoOfEntriesVM<3, TupleId>, // 1 RTreeNoOfEntriesVM<4, TupleId>, // 2 RTreeNoOfEntriesVM<8, TupleId>, // 3 RTreeNoOfEntriesVM<2, TwoLayerLeafInfo>, // 4 RTreeNoOfEntriesVM<3, TwoLayerLeafInfo>, // 5 RTreeNoOfEntriesVM<4, TwoLayerLeafInfo>, // 6 RTreeNoOfEntriesVM<8, TwoLayerLeafInfo> // 7 }; ValueMapping RTreeNoOfNodes [] = { RTreeNoOfNodesVM<2, TupleId>, // 0 RTreeNoOfNodesVM<3, TupleId>, // 1 RTreeNoOfNodesVM<4, TupleId>, // 2 RTreeNoOfNodesVM<8, TupleId>, // 3 RTreeNoOfNodesVM<2, TwoLayerLeafInfo>, // 4 RTreeNoOfNodesVM<3, TwoLayerLeafInfo>, // 5 RTreeNoOfNodesVM<4, TwoLayerLeafInfo>, // 6 RTreeNoOfNodesVM<8, TwoLayerLeafInfo> // 7 }; ValueMapping RTreeBbox [] = { RTreeBboxVM<2, TupleId>, // 0 RTreeBboxVM<3, TupleId>, // 1 RTreeBboxVM<4, TupleId>, // 2 RTreeBboxVM<8, TupleId>, // 3 RTreeBboxVM<2, TwoLayerLeafInfo>, // 4 RTreeBboxVM<3, TwoLayerLeafInfo>, // 5 RTreeBboxVM<4, TwoLayerLeafInfo>, // 6 RTreeBboxVM<8, TwoLayerLeafInfo> // 7 }; ValueMapping RTreeGetRootNode [] = { RTreeGetRootNodeVM<2, TupleId>, // 0 RTreeGetRootNodeVM<3, TupleId>, // 1 RTreeGetRootNodeVM<4, TupleId>, // 2 RTreeGetRootNodeVM<8, TupleId>, // 3 RTreeGetRootNodeVM<2, TwoLayerLeafInfo>, // 4 RTreeGetRootNodeVM<3, TwoLayerLeafInfo>, // 5 RTreeGetRootNodeVM<4, TwoLayerLeafInfo>, // 6 RTreeGetRootNodeVM<8, TwoLayerLeafInfo> // 7 }; /* 5.9.5 Specification Strings for ~treeheight~, ~no\_nodes~, ~no\_entries~, ~bbox~, ~getRootNode~ */ const string RTreeTreeHeightSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" " "\"Example\" \"Comment\" ) " "((rtree -> int" "treeheight( _ )" "Returns the height of the R-tree." "query treeheight(strassen_geoData)" "Always defined. Counting starts with level " "'0' for the root node level." ") )"; const string RTreeNoOfEntriesSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" " "\"Example\" \"Comment\" ) " "((rtree -> int" "no_entries( _ )" "Returns the R-tree's number of entries (stored objects)." "query no_entries(strassen_geoData)" "Always defined." ") )"; const string RTreeNoOfNodesSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" " "\"Example\" \"Comment\" ) " "((rtree -> int" "no_nodes( _ )" "Returns the R-tree's number of nodes." "query no_nodes(strassen_geoData)" "Always defined." ") )"; const string RTreeBboxSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" " "\"Example\" \"Comment\" ) " "((rtree -> rect" "bbox( _ )" "Returns the minimum bounding rectangle for " "the complete R-tree." "query bbox(strassen_geoData)" "Rectangle will be undefined for an empty R-tree." ") )"; const string RTreeGetRootNodeSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" " "\"Example\" \"Comment\" ) " "(rtree -> int" "getRootNode( _ )" "Returns R-tree's record number of root node." "query getRootNode(strassen_geoData)" "Always defined." ") )"; /* 5.9.6 Definitions of ~treeheight~, ~no\_nodes~, ~no\_entries~, ~bbox~, ~getRootNode~ */ Operator rtreetreeheight( "treeheight", // name RTreeTreeHeightSpec, // specification 8, RTreeTreeHeight, // value mapping RTreeInquirySelect, // selection function RTree2IntTypeMap // type mapping ); Operator rtreenoofnodes( "no_nodes", // name RTreeNoOfNodesSpec, // specification 8, RTreeNoOfNodes, // value mapping RTreeInquirySelect, // selection function RTree2IntTypeMap // type mapping ); Operator rtreenoofentries( "no_entries", // name RTreeNoOfEntriesSpec, // specification 8, RTreeNoOfEntries, // value mapping RTreeInquirySelect, // selection function RTree2IntTypeMap // type mapping ); Operator rtreebbox( "bbox", // name RTreeBboxSpec, // specification 8, RTreeBbox, // value mapping RTreeInquirySelect, // selection function RTree2RectTypeMap // type mapping ); Operator rtreegetrootnode( "getRootNode", // name RTreeGetRootNodeSpec, // specification 8, RTreeGetRootNode, // value mapping RTreeInquirySelect, // selection function RTree2IntTypeMap // type mapping ); /* 5.10 Operator ~nodes~ This operator allows introspection of an R-tree. It creates a stream of tuples, each of which describe one node or entry of the R-Tree. Signature is ---- nodes: (rtree) --> stream(tuple((level int) (nodeId int) (MBR rect) (fatherId int) (isLeaf bool) (minEntries int) (maxEntries int) (countEntries int))) ---- */ /* 5.10.1 TypeMapping for Operator ~nodes~ */ ListExpr RTreeNodesTypeMap(ListExpr args) { if(nl->IsEmpty(args) || nl->IsAtom(args) || nl->ListLength(args) != 1){ return listutils::typeError("Expected exactly 1 argument."); }; ListExpr rtreeDescription = nl->First(args); if( !listutils::isRTreeDescription(rtreeDescription ) ){ return listutils::typeError("Expected rtree as 1st argument."); } ListExpr rtreeKeyType = nl->Third(rtreeDescription); ListExpr MBR_ATOM; if( listutils::isKind(rtreeKeyType, Kind::SPATIAL2D()) || listutils::isSymbol(rtreeKeyType, Rectangle<2>::BasicType()) ){ MBR_ATOM = nl->SymbolAtom(Rectangle<2>::BasicType()); } else if( listutils::isKind(rtreeKeyType, Kind::SPATIAL3D()) || listutils::isSymbol(rtreeKeyType, Rectangle<3>::BasicType()) ){ MBR_ATOM = nl->SymbolAtom(Rectangle<3>::BasicType()); } else if( listutils::isKind(rtreeKeyType, Kind::SPATIAL4D()) || listutils::isSymbol(rtreeKeyType, Rectangle<4>::BasicType()) ){ MBR_ATOM = nl->SymbolAtom(Rectangle<4>::BasicType()); } else if( listutils::isKind(rtreeKeyType, Kind::SPATIAL8D()) || listutils::isSymbol(rtreeKeyType, Rectangle<8>::BasicType()) ){ MBR_ATOM = nl->SymbolAtom(Rectangle<8>::BasicType()); } else if( listutils::isKind(rtreeKeyType, Kind::SPATIAL1D()) || listutils::isSymbol(rtreeKeyType, Rectangle<1>::BasicType()) ){ MBR_ATOM = nl->SymbolAtom(Rectangle<1>::BasicType()); } else return listutils::typeError("Unsupported rtree-type."); ListExpr reslist = nl->TwoElemList( nl->SymbolAtom(Symbol::STREAM()), nl->TwoElemList( nl->SymbolAtom(Tuple::BasicType()), nl->Cons( nl->TwoElemList(nl->SymbolAtom("Level"), nl->SymbolAtom(CcInt::BasicType())), nl->Cons( nl->TwoElemList(nl->SymbolAtom("NodeId"), nl->SymbolAtom(CcInt::BasicType())), nl->SixElemList( nl->TwoElemList(nl->SymbolAtom("MBR"), MBR_ATOM), nl->TwoElemList(nl->SymbolAtom("FatherID"), nl->SymbolAtom(CcInt::BasicType())), nl->TwoElemList(nl->SymbolAtom("IsLeaf"), nl->SymbolAtom(CcBool::BasicType())), nl->TwoElemList(nl->SymbolAtom("MinEntries"), nl->SymbolAtom(CcInt::BasicType())), nl->TwoElemList(nl->SymbolAtom("MaxEntries"), nl->SymbolAtom(CcInt::BasicType())), nl->TwoElemList(nl->SymbolAtom("CountEntries"), nl->SymbolAtom(CcInt::BasicType())) ) ) ) ) ); return reslist; } /* 5.10.2 Value Mapping for Operator ~nodes~ */ template int RTreeNodesVM( Word* args, Word& result, int message, Word& local, Supplier s ) { RTreeNodesLocalInfo *lci; switch( message ) { case OPEN: { lci = new RTreeNodesLocalInfo; local.setAddr(lci); lci->firstCall = true; lci->finished = false; lci->resultTupleType = new TupleType(nl->Second(GetTupleResultType(s))); lci->rtree = (R_Tree*) args[0].addr; return 0; } case REQUEST : { if(local.addr == NULL) return CANCEL; lci = (RTreeNodesLocalInfo *)local.addr; if(lci->finished) return CANCEL; IntrospectResult node; if(lci->firstCall) { lci->firstCall = false; lci->finished = !lci->rtree->IntrospectFirst(node); } else { lci->finished = !lci->rtree->IntrospectNext(node); } if( lci->finished ) { return CANCEL; } else { Tuple *tuple = new Tuple( lci->resultTupleType ); tuple->PutAttribute(0, new CcInt(true, node.level)); tuple->PutAttribute(1, new CcInt(true, node.nodeId)); tuple->PutAttribute(2, new Rectangle(node.MBR)); tuple->PutAttribute(3, new CcInt(true, node.fatherId)); tuple->PutAttribute(4, new CcBool(true, node.isLeaf)); tuple->PutAttribute(5, new CcInt(true, node.minEntries)); tuple->PutAttribute(6, new CcInt(true, node.maxEntries)); tuple->PutAttribute(7, new CcInt(true, node.countEntries)); result.setAddr(tuple); return YIELD; } } case CLOSE : { if(local.addr) { lci = (RTreeNodesLocalInfo *)local.addr; lci->resultTupleType->DeleteIfAllowed(); delete lci; local.setAddr(Address(0)); } return 0; } } // end switch cout << "RTreeNodesVM(): Received UNKNOWN message!" << endl; return 0; } /* 5.10.3 Specification for Operator ~nodes~ */ const string RTreeNodesSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" " "\"Example\" \"Comment\" ) " "((rtree (tuple ((x1 t1)...(xn tn))) ti false) " "-> stream(tuple((level int) (nodeId int) (MBR rect) \n" " (fatherId int) (isLeaf bool) \n" " (minEntries int) (maxEntries int) \n" " (countEntries int)))" "nodes( _ )" "Iterates the complete R-tree creating a stream of tuples" "describing all nodes and leaf entries." "" "" ") )"; /* 5.10.4 Selection Function for Operator ~nodes~ */ int RTreeNodesSelect (ListExpr args) { AlgebraManager *algMgr = SecondoSystem::GetAlgebraManager(); ListExpr errorInfo = nl->OneElemList( nl->SymbolAtom( "ERRORS" ) ); string rtreeDescriptionStr; /* handle rtree part of argument */ ListExpr rtreeDescription = nl->First(args); ListExpr rtreeKeyType = nl->Third(rtreeDescription); if( nl->IsEqual(rtreeKeyType, Rectangle<2>::BasicType()) || algMgr->CheckKind(Kind::SPATIAL2D(), rtreeKeyType, errorInfo)) return 0; else if( nl->IsEqual(rtreeKeyType, Rectangle<3>::BasicType()) || algMgr->CheckKind(Kind::SPATIAL3D(), rtreeKeyType, errorInfo)) return 1; else if( nl->IsEqual(rtreeKeyType, Rectangle<4>::BasicType()) || algMgr->CheckKind(Kind::SPATIAL4D(), rtreeKeyType, errorInfo)) return 2; else if( nl->IsEqual(rtreeKeyType, Rectangle<8>::BasicType()) || algMgr->CheckKind(Kind::SPATIAL8D(), rtreeKeyType, errorInfo)) return 3; else if( nl->IsEqual(rtreeKeyType, Rectangle<1>::BasicType()) || algMgr->CheckKind(Kind::SPATIAL1D(), rtreeKeyType, errorInfo)) return 4; return -1; } ValueMapping RTreeNodes [] = { RTreeNodesVM<2>, RTreeNodesVM<3>, RTreeNodesVM<4>, RTreeNodesVM<8>, RTreeNodesVM<1>}; /* 5.10.2 Definition of Operator ~nodes~ */ Operator rtreenodes( "nodes", // name RTreeNodesSpec, // specification 5, RTreeNodes, // value mapping RTreeNodesSelect, // selection function RTreeNodesTypeMap // type mapping ); /* 5.10.3 Definition of Operator ~entries~ */ const string RTreeEntriesSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" " "\"Example\" \"Comment\" ) " "((rtree (tuple ((x1 t1)...(xn tn))) ti false) " "-> stream(tuple((nodeid int)(bbox key)(tid tupleid))" "entries( _ )" "Returns a stream of tuples which are all the nodes contain bbox in" "a leaf entry." "" "" ") )"; template int RTreeEntriesVM( Word* args, Word& result, int message, Word& local, Supplier s ) { RTreeNodesLocalInfo *lci; IntrospectResult node; switch( message ) { case OPEN: { lci = new RTreeNodesLocalInfo; local.setAddr(lci); lci->firstCall = true; lci->finished = false; lci->resultTupleType = new TupleType(nl->Second(GetTupleResultType(s))); lci->rtree = (R_Tree*) args[0].addr; if(lci->firstCall) { lci->firstCall = false; lci->finished = !lci->rtree->IntrospectFirst(node); } return 0; } case REQUEST : { static int level = 0; unsigned long nodeid; static unsigned long tupleid; static BBox box; if(local.addr == NULL) return CANCEL; lci = (RTreeNodesLocalInfo *)local.addr; if(lci->finished) return CANCEL; if(level == 0){ lci->finished = !lci->rtree->IntrospectNextE(nodeid,box,tupleid); level = lci->rtree->Height(); if( lci->finished ){ level = 0; return CANCEL; } Tuple *tuple = new Tuple( lci->resultTupleType ); tuple->PutAttribute(0, new CcInt(true, nodeid)); tuple->PutAttribute(1, new Rectangle(box)); tuple->PutAttribute(2, new CcInt(true, tupleid)); result.setAddr(tuple); return YIELD; }else{ level--; nodeid = lci->rtree->SmiNodeId(level); Tuple *tuple = new Tuple( lci->resultTupleType ); tuple->PutAttribute(0, new CcInt(true, nodeid)); tuple->PutAttribute(1, new Rectangle(box)); tuple->PutAttribute(2, new CcInt(true, tupleid)); result.setAddr(tuple); return YIELD; } } case CLOSE : { if(local.addr) { lci = (RTreeNodesLocalInfo *)local.addr; lci->resultTupleType->DeleteIfAllowed(); delete lci; local.setAddr(Address(0)); } return 0; } } // end switch cout << "RTreeEntriesVM(): Received UNKNOWN message!" << endl; return 0; } ValueMapping RTreeEntries[] = { RTreeEntriesVM<2,TupleId>, // 0 RTreeEntriesVM<3,TupleId>, // 1 RTreeEntriesVM<4,TupleId>, // 2 RTreeEntriesVM<8,TupleId>, RTreeEntriesVM<1,TupleId>}; int RTreeEntriesSelect (ListExpr args) { AlgebraManager *algMgr = SecondoSystem::GetAlgebraManager(); ListExpr errorInfo = nl->OneElemList( nl->SymbolAtom( "ERRORS" ) ); string rtreeDescriptionStr; /* handle rtree part of argument */ ListExpr rtreeDescription = nl->First(args); ListExpr rtreeKeyType = nl->Third(rtreeDescription); if( nl->IsEqual(rtreeKeyType, Rectangle<2>::BasicType()) || algMgr->CheckKind(Kind::SPATIAL2D(), rtreeKeyType, errorInfo)) return 0; else if( nl->IsEqual(rtreeKeyType, Rectangle<3>::BasicType()) || algMgr->CheckKind(Kind::SPATIAL3D(), rtreeKeyType, errorInfo)) return 1; else if( nl->IsEqual(rtreeKeyType, Rectangle<4>::BasicType()) || algMgr->CheckKind(Kind::SPATIAL4D(), rtreeKeyType, errorInfo)) return 2; else if( nl->IsEqual(rtreeKeyType, Rectangle<8>::BasicType()) || algMgr->CheckKind(Kind::SPATIAL8D(), rtreeKeyType, errorInfo)) return 3; else if( nl->IsEqual(rtreeKeyType, Rectangle<1>::BasicType()) || algMgr->CheckKind(Kind::SPATIAL1D(), rtreeKeyType, errorInfo)) return 4; return -1; } /* Value mapping for ~entries~ */ ListExpr RTreeEntriesTypeMap(ListExpr args) { if(nl->IsEmpty(args) || nl->IsAtom(args) || nl->ListLength(args) != 1){ return listutils::typeError("Expected exactly 1 argument."); }; ListExpr rtreeDescription = nl->First(args); if( !listutils::isRTreeDescription(rtreeDescription ) ){ return listutils::typeError("Expected rtree as 1st argument."); } ListExpr rtreeKeyType = nl->Third(rtreeDescription); ListExpr MBR_ATOM; if( listutils::isKind(rtreeKeyType, Kind::SPATIAL2D()) || listutils::isSymbol(rtreeKeyType, Rectangle<2>::BasicType()) ){ MBR_ATOM = nl->SymbolAtom(Rectangle<2>::BasicType()); } else if( listutils::isKind(rtreeKeyType, Kind::SPATIAL3D()) || listutils::isSymbol(rtreeKeyType, Rectangle<3>::BasicType()) ){ MBR_ATOM = nl->SymbolAtom(Rectangle<3>::BasicType()); } else if( listutils::isKind(rtreeKeyType, Kind::SPATIAL4D()) || listutils::isSymbol(rtreeKeyType, Rectangle<4>::BasicType()) ){ MBR_ATOM = nl->SymbolAtom(Rectangle<4>::BasicType()); } else if( listutils::isKind(rtreeKeyType, Kind::SPATIAL8D()) || listutils::isSymbol(rtreeKeyType, Rectangle<8>::BasicType()) ){ MBR_ATOM = nl->SymbolAtom(Rectangle<8>::BasicType()); } else if( listutils::isKind(rtreeKeyType, Kind::SPATIAL1D()) || listutils::isSymbol(rtreeKeyType, Rectangle<1>::BasicType()) ){ MBR_ATOM = nl->SymbolAtom(Rectangle<1>::BasicType()); } else return listutils::typeError("Unsupported rtree-type."); ListExpr reslist = nl->TwoElemList( nl->SymbolAtom(Symbol::STREAM()), nl->TwoElemList( nl->SymbolAtom(Tuple::BasicType()), nl->Cons( nl->TwoElemList(nl->SymbolAtom("Nodeid"), nl->SymbolAtom(CcInt::BasicType())), nl->TwoElemList(nl->TwoElemList(nl->SymbolAtom("MBR"), MBR_ATOM), nl->TwoElemList(nl->SymbolAtom("Tupleid"), nl->SymbolAtom(CcInt::BasicType())) ) ) ) ); return reslist; } Operator rtreeentries( "entries", // name RTreeEntriesSpec, // specification 5, RTreeEntries, // value mapping RTreeEntriesSelect, // selection function RTreeEntriesTypeMap // type mapping ); /* 5.12 Operator ~getFileInfo~ Returns a text object with statistical information on all files used by the rtree. The result has format ~file\_stat\_result~: ---- file_stat_result --> (file_stat_list) file_stat_list --> epsilon | file_statistics file_stat_list file_statistics --> epsilon | file_stat_field file_statistics file_stat_field --> ((keyname) (value)) keyname --> string value --> string ---- 5.12.1 TypeMapping of operator ~getFileInfo~ Uses ~RTree2TextTypeMap~. 5.12.2 ValueMapping of operator ~getFileInfo~ */ template int getFileInfoRtreeValueMap(Word* args, Word& result, int message, Word& local, Supplier s) { result = qp->ResultStorage(s); FText* restext = (FText*)(result.addr); R_Tree *rtree = (R_Tree *)(args[0].addr); SmiStatResultType resVector(0); if ( (rtree != 0) && rtree->getFileStats(resVector) ){ string resString = "[[\n"; for(SmiStatResultType::iterator i = resVector.begin(); i != resVector.end(); ){ resString += "\t[['" + i->first + "'],['" + i->second + "']]"; if(++i != resVector.end()){ resString += ",\n"; } else { resString += "\n"; } } resString += "]]"; restext->Set(true,resString); } else { restext->Set(false,""); } return 0; }; ValueMapping getFileInfoRtreeValueMapArray[] = { getFileInfoRtreeValueMap<2, TupleId>, // 0 getFileInfoRtreeValueMap<3, TupleId>, // 1 getFileInfoRtreeValueMap<4, TupleId>, // 2 getFileInfoRtreeValueMap<8, TupleId>, // 3 getFileInfoRtreeValueMap<2, TwoLayerLeafInfo>, // 4 getFileInfoRtreeValueMap<3, TwoLayerLeafInfo>, // 5 getFileInfoRtreeValueMap<4, TwoLayerLeafInfo>, // 6 getFileInfoRtreeValueMap<8, TwoLayerLeafInfo> // 7 }; /* 5.12.3 Selection Function for operator ~getFileInfo~ Uses ~RTreeInquirySelect~. 5.12.4 Specification of operator ~getFileInfo~ */ const string getFileInfoRtreeSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " "( (btree(tuple(x) ti) xi -> text)" "getFileInfo( _ )" "Retrieve statistical infomation on the file(s) used by the rtree " "instance." "query getFileInfo(Trains_Trip_rtree)" ") )"; /* 5.12.5 Definition of operator ~getFileInfo~ */ Operator getfileinfortree( "getFileInfo", // name getFileInfoRtreeSpec, // specification 8, // number of value mapping functions getFileInfoRtreeValueMapArray, // value mapping RTreeInquirySelect, // selection function RTree2TextTypeMap // type mapping ); const string UpdatebulkloadrtreeSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" " "\"Example\" \"Comment\" ) " "((stream (tuple (x1 t1)...(xn tn) (id tid))) xi)" " -> (rtree (tuple ((x1 t1)...(xn tn))) ti false)\n" "((stream (tuple (x1 t1)...(xn tn) " "(id tid)(low int)(high int))) xi)" " -> (rtree (tuple ((x1 t1)...(xn tn))) ti true)" "_ _ updatebulkloadrtree [ _ ]" "Creates an rtree applying bulk loading on an existing file." "This means, the operator expects the input stream of tuples to be ordered " "in some meaningful way in order to reduce overlapping of " "bounding boxes (e.g. a Z-ordering on the bounding boxes). " "The R-Tree is created bottom up by gouping as many entries as " "possible into the leaf nodes and then creating the higher levels. " "The key type ti must be of kind SPATIAL2D, SPATIAL3D, SPATIAL4D " "or Spatial8D, or of type rect, rect2, rect3, rect4 or rect8." "let UTOrdered_2 = UTOrdered_1 UTOrdered feed addid sortby[UTrip asc] " "filter[tid2int(.TID) > 30000] updatebulkloadrtree[UTrip]" "" ") )"; /* UpdateBulkLoad for r-tree */ ListExpr UpdateBulkLoadTypeMap(ListExpr args) { // cout<<"UpdateBulkLoadTypeMap"<IsEmpty(args) || nl->ListLength(args) != 3){ return listutils::typeError("Expecting exactly 3 arguments."); } // split to parameters ListExpr tupleStream = nl->Second(args), attrNameLE = nl->Third(args); ///////////////////////////////////////////////////////// ListExpr firstpara = nl->First(args); if(nl->ListLength(firstpara) != 4){ string err = "rtree(tuple(...) rect3 BOOL) expected"; ErrorReporter::ReportError(err); return nl->TypeError(); } if(!(nl->IsEqual(nl->First(firstpara),RTree2TID::BasicType()) || nl->IsEqual(nl->First(firstpara),RTree3TID::BasicType()) || nl->IsEqual(nl->First(firstpara),RTree4TID::BasicType()) || nl->IsEqual(nl->First(firstpara),RTree8TID::BasicType()))){ string err = "rtree(tuple(...) rect3 BOOL) expected"; ErrorReporter::ReportError(err); return nl->TypeError(); } /////////////////////////////////////////////////////////// // check stream if(!listutils::isTupleStream(tupleStream)){ return listutils::typeError("Expecting a tuplestream as 1st argument."); } // check key attribute name if(!listutils::isSymbol(attrNameLE)){ return listutils::typeError("Expecting an attribute name as 2nd argument."); } string attrName = nl->SymbolValue(attrNameLE); // check if key attribute is from stream ListExpr attrList = nl->Second(nl->Second(tupleStream)); ListExpr attrType; int attrIndex = listutils::findAttribute(attrList, attrName, attrType); if(attrIndex <= 0){ return listutils::typeError("Expecting the attribute (2nd argument) being " "part of the tuplestream (1st argument)."); } // check for type of key attribute if( !(listutils::isSpatialType(attrType) || listutils::isRectangle(attrType))) { return listutils::typeError("Expecting the key attribute (2nd argument) " "being of kind SPATIAL2D, SPATIAL3D, Spatial4D or SPATIAL8D, of of " "type rect, rect3, rect4, or rect8."); } string rtreetype; if( listutils::isKind(attrType, Kind::SPATIAL2D()) || listutils::isSymbol(attrType, Rectangle<2>::BasicType())){ rtreetype = RTree2TID::BasicType(); } else if( listutils::isKind(attrType, Kind::SPATIAL3D()) || listutils::isSymbol(attrType, Rectangle<3>::BasicType())){ rtreetype = RTree3TID::BasicType(); } else if( listutils::isKind(attrType, Kind::SPATIAL4D()) || listutils::isSymbol(attrType, Rectangle<4>::BasicType())){ rtreetype = RTree4TID::BasicType(); } else if( listutils::isKind(attrType, Kind::SPATIAL8D()) || listutils::isSymbol(attrType, Rectangle<8>::BasicType())){ rtreetype = RTree8TID::BasicType(); } else if( listutils::isKind(attrType, Kind::SPATIAL1D()) || listutils::isSymbol(attrType, Rectangle<1>::BasicType())){ rtreetype = RTree1TID::BasicType(); } else return listutils::typeError("Unsupported key type."); /* Now we have two possibilities: - multi-entry indexing, or - double indexing For multi-entry indexing, one and only one of the attributes must be a tuple identifier. In the latter, together with a tuple identifier, the last two attributes must be of integer type (~int~). In the first case, a standard R-Tree is created possibly containing several entries to the same tuple identifier, and in the latter, a double index R-Tree is created using as low and high parameters these two last integer numbers. */ ListExpr first, rest, newAttrList=nl->TheEmptyList(), lastNewAttrList=nl->TheEmptyList(); int tidIndex = 0; string type; bool firstcall = true, doubleIndex = false; int nAttrs = nl->ListLength( attrList ); rest = attrList; int j = 1; while (!nl->IsEmpty(rest)) { first = nl->First(rest); rest = nl->Rest(rest); type = nl->SymbolValue(nl->Second(first)); if (type == TupleIdentifier::BasicType()) { if( tidIndex != 0 ){ return listutils::typeError("Expecting exactly one attribute of type " "'tid' in the 1st argument."); } tidIndex = j; } else if( j == nAttrs - 1 && type == CcInt::BasicType() && nl->SymbolValue( nl->Second(nl->First(rest))) == CcInt::BasicType() ) { // the last two attributes are integers doubleIndex = true; } else { if (firstcall) { firstcall = false; newAttrList = nl->OneElemList(first); lastNewAttrList = newAttrList; } else { lastNewAttrList = nl->Append(lastNewAttrList, first); } } j++; } if( tidIndex == 0 ){ return listutils::typeError("Expecting exactly one attribute of type " "'tid' in the 1st argument."); } return nl->ThreeElemList( nl->SymbolAtom(Symbol::APPEND()), nl->TwoElemList( nl->IntAtom(attrIndex), nl->IntAtom(tidIndex)), nl->FourElemList( nl->SymbolAtom(rtreetype), nl->TwoElemList( nl->SymbolAtom(Tuple::BasicType()), newAttrList), attrType, nl->BoolAtom(doubleIndex))); } /* Bulkload an R-tree with an input R-tree so that they map to the same file */ template int UpdateBulkLoadFun(Word* args, Word& result, int message,Word& local, Supplier s) { // const int dim = 3; Word wTuple; //R_Tree<3,TupleId>* rtree_in1 = static_cast*>(args[0].addr); //R_Tree<3,TupleId>* rtree_temp = (R_Tree<3,TupleId>*)qp->ResultStorage(s).addr; R_Tree* rtree_in1 = static_cast*>(args[0].addr); R_Tree* rtree_temp = (R_Tree*)qp->ResultStorage(s).addr; rtree_temp->CloseFile(); // R_Tree *rtree = // new R_Tree<3,TupleId>(rtree_in1->FileId(),4000); R_Tree *rtree = new R_Tree(rtree_in1->FileId(),4000); int attrIndex = ((CcInt*)args[3].addr)->GetIntval() - 1, tidIndex = ((CcInt*)args[4].addr)->GetIntval() - 1; // Get a reference to the message center static MessageCenter* msg = MessageCenter::GetInstance(); int count = 0; // counter for progress indicator bool BulkLoadInitialized = rtree->InitializeBulkLoad(); assert(BulkLoadInitialized); qp->Open(args[1].addr); qp->Request(args[1].addr, wTuple); while (qp->Received(args[1].addr)) { if ((count++ % 10000) == 0) { // send the message, the message center will call // the registered handlers. Normally the client applications // will register them. msg->Send(nl, listutils::simpleMessage(count)); } Tuple* tuple = (Tuple*)wTuple.addr; if( ((StandardSpatialAttribute*)tuple-> GetAttribute(attrIndex))->IsDefined() && ((TupleIdentifier *)tuple->GetAttribute(tidIndex))-> IsDefined() ) { BBox box = ((StandardSpatialAttribute*)tuple-> GetAttribute(attrIndex))->BoundingBox(); if (box.IsDefined()) { R_TreeLeafEntry e( box, ((TupleIdentifier *)tuple-> GetAttribute(tidIndex))->GetTid() ); rtree->InsertBulkLoad(e); } } tuple->DeleteIfAllowed(); qp->Request(args[1].addr, wTuple); } qp->Close(args[1].addr); int FinalizedBulkLoad = rtree->FinalizeBulkLoad(); assert( FinalizedBulkLoad ); // send the message, the message center will call // the registered handlers. Normally the client applications // will register them. msg->Send(nl, listutils::simpleMessage(count)); rtree->SwitchHeader(rtree_in1); result.setAddr(rtree); return 0; } /* Build RTree on new coming units and store it into an existing RTree file */ ValueMapping VMUpdateBulkLoadFun[]= { UpdateBulkLoadFun<2>, UpdateBulkLoadFun<3>, UpdateBulkLoadFun<4>, UpdateBulkLoadFun<8>, UpdateBulkLoadFun<1> }; /* 5.2. Selection Function for Operator ~creatertree\_bulkload~ */ int UpdateBulkLoadSelect (ListExpr args) { // ListExpr relDescription = nl->First(args), // attrNameLE = nl->Second(args), // tupleDescription = nl->Second(relDescription), // attrList = nl->Second(tupleDescription); ListExpr relDescription = nl->Second(args), attrNameLE = nl->Third(args), tupleDescription = nl->Second(relDescription), attrList = nl->Second(tupleDescription); string attrName = nl->SymbolValue(attrNameLE); ListExpr attrType; FindAttribute(attrList, attrName, attrType); AlgebraManager* algMgr = SecondoSystem::GetAlgebraManager(); ListExpr errorInfo = nl->OneElemList( nl->SymbolAtom( "ERRORS" ) ); int result; if ( algMgr->CheckKind(Kind::SPATIAL2D(), attrType, errorInfo) ) result = 0; else if ( algMgr->CheckKind(Kind::SPATIAL3D(), attrType, errorInfo) ) result = 1; else if ( algMgr->CheckKind(Kind::SPATIAL4D(), attrType, errorInfo) ) result = 2; else if ( algMgr->CheckKind(Kind::SPATIAL8D(), attrType, errorInfo) ) result = 3; else if ( algMgr->CheckKind(Kind::SPATIAL1D(), attrType, errorInfo) ) result = 4; else return -1; /* should not happen */ if( nl->SymbolValue(nl->First(relDescription)) == Symbol::STREAM()) { //ListExpr first, ListExpr rest = attrList; while (!nl->IsEmpty(rest)) { // first = nl->First(rest); rest = nl->Rest(rest); } return result; } return -1; } Operator updatebulkloadrtree( "updatebulkloadrtree", UpdatebulkloadrtreeSpec, 5, VMUpdateBulkLoadFun, UpdateBulkLoadSelect, UpdateBulkLoadTypeMap ); /* 5.13 Operator ~getNodeInfo~ This operator allows introspection of an RTree. It creates a stream of a tuple, which describes one node of the R-Tree. The node is selected by the given recordnumber (int-value). The stream is empty, if the given recordnumber is not existing/not valid. MBRsize is the size of the node-MBR, MBRdead is the size of the node-MBR, which is not covered by a son-MBR, MBRoverlapSize is the size of the node-MBR, where two (or more) son-MBRs overlap, MBRoverlapsNo is the count of overlapping son-MBRs and MBRdensity is the number of son-MBRs per MBRsize. Signature is ---- getNodeInfo: (rtree) x int --> stream(tuple((NodeId int) (MBR rect) (NoOfSons int) (IsLeafNode bool) (IsRootNode bool) (MBRsize real) (MBRdead real) (MBRoverlapSize real) (MBRoverlapsNo int) (MBRdensity real))) ---- */ /* 5.13.1 TypeMapping for Operator ~getNodeInfo~ The typemapping function uses a template parameter InfoType to differ between the typemapping of the operators ~getNodeInfo~, ~getNodeSons~ and ~getLeafEntries~. The typemapping of operator ~getNodeInfo~ uses InfoType = NODEINFO. */ enum InfoType { NODEINFO, NODESONS, LEAFENTRIES }; template ListExpr RTreeGetInfoTypeTypeMap(ListExpr args) { if(nl->IsEmpty(args) || nl->IsAtom(args) || nl->ListLength(args) != 2){ return listutils::typeError("Expected exactly 2 arguments."); }; // test first argument for rtree ListExpr rtreeDescription = nl->First(args); if( !listutils::isRTreeDescription(rtreeDescription ) ){ return listutils::typeError("Expected rtree as 1st argument."); } // check type of rtree ListExpr rtreeKeyType = nl->Third(rtreeDescription); ListExpr MBR_ATOM; if( listutils::isKind(rtreeKeyType, Kind::SPATIAL2D()) || listutils::isSymbol(rtreeKeyType, Rectangle<2>::BasicType()) ){ MBR_ATOM = nl->SymbolAtom(Rectangle<2>::BasicType()); } else if( listutils::isKind(rtreeKeyType, Kind::SPATIAL3D()) || listutils::isSymbol(rtreeKeyType, Rectangle<3>::BasicType()) ){ MBR_ATOM = nl->SymbolAtom(Rectangle<3>::BasicType()); } else if( listutils::isKind(rtreeKeyType, Kind::SPATIAL4D()) || listutils::isSymbol(rtreeKeyType, Rectangle<4>::BasicType()) ){ MBR_ATOM = nl->SymbolAtom(Rectangle<4>::BasicType()); } else if( listutils::isKind(rtreeKeyType, Kind::SPATIAL8D()) || listutils::isSymbol(rtreeKeyType, Rectangle<8>::BasicType()) ){ MBR_ATOM = nl->SymbolAtom(Rectangle<8>::BasicType()); } else if( listutils::isKind(rtreeKeyType, Kind::SPATIAL1D()) || listutils::isSymbol(rtreeKeyType, Rectangle<1>::BasicType()) ){ MBR_ATOM = nl->SymbolAtom(Rectangle<1>::BasicType()); } else return listutils::typeError("Unsupported rtree-type."); // test second argument for integer ListExpr RecNumber = nl->Second(args); if ( !nl->IsAtom(RecNumber) || !listutils::isNumericType(RecNumber) ) { return listutils::typeError("Expecting int as second argument."); } ListExpr reslist = nl->Empty(); switch (iTyp) { case NODEINFO: { reslist = nl->TwoElemList( nl->SymbolAtom(Symbol::STREAM()), nl->TwoElemList( nl->SymbolAtom(Tuple::BasicType()), nl->Cons( nl->TwoElemList(nl->SymbolAtom("NodeId"), nl->SymbolAtom(CcInt::BasicType())), nl->Cons( nl->TwoElemList(nl->SymbolAtom("MBR"), MBR_ATOM), nl->Cons( nl->TwoElemList(nl->SymbolAtom("NoOfSons"), nl->SymbolAtom(CcInt::BasicType())), nl->Cons( nl->TwoElemList(nl->SymbolAtom("IsLeafNode"), nl->SymbolAtom(CcBool::BasicType())), nl->SixElemList( nl->TwoElemList(nl->SymbolAtom("IsRootNode"), nl->SymbolAtom(CcBool::BasicType())), nl->TwoElemList(nl->SymbolAtom("MBRsize"), nl->SymbolAtom(CcReal::BasicType())), nl->TwoElemList(nl->SymbolAtom("MBRdead"), nl->SymbolAtom(CcReal::BasicType())), nl->TwoElemList(nl->SymbolAtom("MBRoverlapSize"), nl->SymbolAtom(CcReal::BasicType())), nl->TwoElemList(nl->SymbolAtom("MBRoverlapsNo"), nl->SymbolAtom(CcInt::BasicType())), nl->TwoElemList(nl->SymbolAtom("MBRdensity"), nl->SymbolAtom(CcReal::BasicType())) ))))))); break; } case NODESONS: { reslist = nl->TwoElemList( nl->SymbolAtom(Symbol::STREAM()), nl->TwoElemList( nl->SymbolAtom(Tuple::BasicType()), nl->Cons( nl->TwoElemList(nl->SymbolAtom("NodeId"), nl->SymbolAtom(CcInt::BasicType())), nl->TwoElemList( nl->TwoElemList(nl->SymbolAtom("SonId"), nl->SymbolAtom(CcInt::BasicType())), nl->TwoElemList(nl->SymbolAtom("SonMBR"), MBR_ATOM) )))); break; } case LEAFENTRIES: { reslist = nl->TwoElemList( nl->SymbolAtom(Symbol::STREAM()), nl->TwoElemList( nl->SymbolAtom(Tuple::BasicType()), nl->Cons( nl->TwoElemList(nl->SymbolAtom("NodeId"), nl->SymbolAtom(CcInt::BasicType())), nl->TwoElemList( nl->TwoElemList(nl->SymbolAtom("TupleID"), nl->SymbolAtom(TupleIdentifier::BasicType())), nl->TwoElemList(nl->SymbolAtom("EntryMBR"), MBR_ATOM) )))); break; } } return reslist; } /* 5.13.2 Value Mapping for Operator ~getNodeInfo~ */ template struct GetSonsInfo{ int index; int maxEntries; R_TreeNode* father; TupleType* ttype; long nodeId; bool IsRoot; GetSonsInfo( int i, int m, R_TreeNode* f, TupleType* tt, long ni, bool ir) : index(i), maxEntries(m), father(f), ttype(tt), nodeId(ni), IsRoot(ir) {} }; /* Structure to handle the information of the interesting node. */ template bool checkRecordId(R_Tree* rtree, int nodeId) { bool findRID = false; if ( (nodeId > 0) && (nodeId != static_cast(rtree->HeaderRecordId())) && (nodeId < rtree->NodeCount()+2)) findRID = true; return findRID; } /* Checks if the given nodeId is valid in rtree. */ struct seg_node { double bottom, top; int count; double measure; seg_node *left, *right; seg_node(double b, double t): bottom(b), top(t), count(0), measure(0.0), left(0), right(0) {} }; /* node-structure of the segment tree used for 2D-sweepline */ struct quad_node { double left, right, bottom, top; int count; double measure; quad_node *bottomleft, *bottomright, *topleft, *topright; quad_node(double l, double r, double b, double t): left(l), right(r), bottom(b), top(t), count(0), measure(0.0), bottomleft(0), bottomright(0), topleft(0), topright(0) {} }; /* node-structure of the quad tree used for sweepline with dimensions dim $ >=$ 3 */ struct event { double xVal; int index; event(): xVal(0.), index(0) {} event(double x, int i): xVal(x), index(i) {} }; struct eventComp { bool operator() (const event& lhs, const event& rhs) const { return lhs.xVal &yVals) { seg_node* sTree; set::iterator yValiter = yVals.begin(); if (yVals.size()==2) { //segment is the new leaf double b = *yValiter++; double t = *yValiter; sTree = new seg_node(b,t); } else { //divide the list in the middle int subsetSize = yVals.size()/2; for (int i=0; i yValsRight (yValiter++, yVals.end()); set yValsLeft (yVals.begin(), yValiter); //left element of right list is equal to //right element of the left list seg_node* sTreeLeft = buildTree(yValsLeft); seg_node* sTreeRight = buildTree(yValsRight); //create new node with trees of the two sublists sTree = new seg_node(sTreeLeft->bottom, sTreeRight->top); sTree->left = sTreeLeft; sTree->right = sTreeRight; } return sTree; } /* builds the segment tree for the given sorted set of y-values */ void deleteSegTree(seg_node* segTree) { if (segTree==0) return; deleteSegTree(segTree->left); deleteSegTree(segTree->right); delete segTree; segTree = 0; } /* deletes the segment tree */ quad_node* buildTree(set &yVals, set &zVals) { quad_node* qTree; set::iterator yValiter = yVals.begin(); set::iterator zValiter = zVals.begin(); if ((yVals.size()==2)&&(zVals.size()==2)) { //quad is the new leaf double l = *yValiter++; double r = *yValiter; double b = *zValiter++; double t = *zValiter; qTree = new quad_node(l, r, b, t); } else if (yVals.size()==2) { //divide the z-list in the middle int subsetSizeZ = zVals.size()/2; for (int i=0; i zValsTop (zValiter++, zVals.end()); set zValsBottom (zVals.begin(), zValiter); //top element of bottom list is equal to //bottom element of the top list quad_node* qTreeBottom = buildTree(yVals, zValsBottom); quad_node* qTreeTop = buildTree(yVals, zValsTop); //create new node with trees of the two sublists qTree = new quad_node(qTreeBottom->left, qTreeTop->right, qTreeBottom->bottom, qTreeTop->top); qTree->bottomright = qTreeBottom; qTree->topright = qTreeTop; } else if (zVals.size()==2) { //divide the y-list in the middle int subsetSizeY = yVals.size()/2; for (int i=0; i yValsRight (yValiter++, yVals.end()); set yValsLeft (yVals.begin(), yValiter); //left element of right list is equal to //right element of the left list quad_node* qTreeLeft = buildTree(yValsLeft, zVals); quad_node* qTreeRight = buildTree(yValsRight, zVals); //create new node with trees of the two sublists qTree = new quad_node(qTreeLeft->left, qTreeRight->right, qTreeLeft->bottom, qTreeRight->top); qTree->topleft = qTreeLeft; qTree->topright = qTreeRight; } else { //divide the two list in the middle int subsetSizeY = yVals.size()/2; for (int i=0; i yValsRight (yValiter++, yVals.end()); set yValsLeft (yVals.begin(), yValiter); //left element of right list is equal to //right element of the left list int subsetSizeZ = zVals.size()/2; for (int i=0; i zValsTop (zValiter++, zVals.end()); set zValsBottom (zVals.begin(), zValiter); //top element of bottom list is equal to //bottom element of the top list quad_node* qTreeBottomLeft = buildTree(yValsLeft, zValsBottom); quad_node* qTreeBottomRight = buildTree(yValsRight, zValsBottom); quad_node* qTreeTopLeft = buildTree(yValsLeft, zValsTop); quad_node* qTreeTopRight = buildTree(yValsRight, zValsTop); //create new node with trees of the two sublists qTree = new quad_node(qTreeBottomLeft->left, qTreeTopRight->right, qTreeBottomLeft->bottom, qTreeTopRight->top); qTree->bottomleft = qTreeBottomLeft; qTree->bottomright = qTreeBottomRight; qTree->topleft = qTreeTopLeft; qTree->topright = qTreeTopRight; } return qTree; } /* builds the quad tree for the given sorted set of y- and z-values */ void deleteQuadTree(quad_node* quadTree) { if (quadTree==0) return; deleteQuadTree(quadTree->bottomleft); deleteQuadTree(quadTree->bottomright); deleteQuadTree(quadTree->topleft); deleteQuadTree(quadTree->topright); delete quadTree; quadTree = 0; } /* deletes the quad tree */ void deleteNode(seg_node* sTree, double b, double t) { if ((sTree->bottom >= b)&&(sTree->top <= t)) { sTree->count--; if (sTree->count==0) sTree->measure = 0; } else { if (b < sTree->left->top) deleteNode(sTree->left, b, t); if (sTree->right->bottom < t) deleteNode(sTree->right, b, t); if (sTree->count == 0) sTree->measure = sTree->left->measure + sTree->right->measure; } } /* deletes the entry of segment (b)-(t) in the segment tree */ void insertNode(seg_node* sTree, double b, double t) { if ((sTree->bottom >= b)&&(sTree->top <= t)) { sTree->count++; if (sTree->count==1) sTree->measure = sTree->top - sTree->bottom; } else { if (b < sTree->left->top) insertNode(sTree->left, b, t); if (sTree->right->bottom < t) insertNode(sTree->right, b, t); if (sTree->count == 0) sTree->measure = sTree->left->measure + sTree->right->measure; } } /* inserts the entry of segment (b)-(t) in the segment tree */ void deleteNode(quad_node* sTree, double l, double r, double b, double t) { if ((sTree->left >= l)&&(sTree->right <= r) &&(sTree->bottom >= b)&&(sTree->top <= t)) { sTree->count--; if (sTree->count==0) sTree->measure = 0.0; } else { if ((sTree->bottomleft) &&(sTree->bottomleft->left < r)&&(sTree->bottomleft->bottom < t)) deleteNode(sTree->bottomleft, l, r, b, t); if ((sTree->bottomright) &&(l < sTree->bottomright->right)&&(sTree->bottomright->bottom < t)) deleteNode(sTree->bottomright, l, r , b, t); if ((sTree->topleft) &&(sTree->topleft->left < r)&&(b < sTree->topleft->top)) deleteNode(sTree->topleft, l, r, b, t); if ((sTree->topright) &&(l < sTree->topright->right)&&(b < sTree->topright->top)) deleteNode(sTree->topright, l, r , b, t); if (sTree->count == 0) { sTree->measure = 0.0; if (sTree->bottomleft) sTree->measure += sTree->bottomleft->measure; if (sTree->bottomright) sTree->measure += sTree->bottomright->measure; if (sTree->topleft) sTree->measure += sTree->topleft->measure; if (sTree->topright) sTree->measure += sTree->topright->measure; } } } /* deletes the entry of rectangle (l,b)-(r,t) in the quad tree */ void insertNode(quad_node* sTree, double l, double r, double b, double t) { if ((sTree->left >= l)&&(sTree->right <= r) &&(sTree->bottom >= b)&&(sTree->top <= t)) { sTree->count++; if (sTree->count==1) sTree->measure = (sTree->right - sTree->left) * (sTree->top - sTree->bottom); } else { if ((sTree->bottomleft) &&(sTree->bottomleft->left < r)&&(sTree->bottomleft->bottom < t)) insertNode(sTree->bottomleft, l, r, b, t); if ((sTree->bottomright) &&(l < sTree->bottomright->right)&&(sTree->bottomright->bottom < t)) insertNode(sTree->bottomright, l, r , b, t); if ((sTree->topleft) &&(sTree->topleft->left < r)&&(b < sTree->topleft->top)) insertNode(sTree->topleft, l, r, b, t); if ((sTree->topright) &&(l < sTree->topright->right)&&(b < sTree->topright->top)) insertNode(sTree->topright, l, r , b, t); if (sTree->count == 0) { sTree->measure = 0.0; if (sTree->bottomleft) sTree->measure += sTree->bottomleft->measure; if (sTree->bottomright) sTree->measure += sTree->bottomright->measure; if (sTree->topleft) sTree->measure += sTree->topleft->measure; if (sTree->topright) sTree->measure += sTree->topright->measure; } } } /* inserts the entry of rectangle (l,b)-(r,t) in the quad tree */ template double getSweepAreas2D(vector< Rectangle > BBox) { if (dim!=2) return 0.0; //SweepLine with segmenttree only for dim=2 if (BBox.empty()) return 0.0; //area of empty rectangle is 0 unsigned int it = 0; //remove rectangles with size=0 (e.g. points/lines) while (it xVals; set yVals; multiset insertMBR; multiset deleteMBR; multiset::iterator iterateInsert; multiset::iterator iterateDelete; for (unsigned int i=0; i::iterator xValiter; xValiter = xVals.begin(); iterateInsert = insertMBR.begin(); iterateDelete = deleteMBR.begin(); x = *xValiter; xValiter++; while (xValiter != xVals.end()) { //sweep line for all x-values while ((iterateDelete!=deleteMBR.end())&& ((*iterateDelete).xVal == x)) { //delete segments from tree at position x int index = (*iterateDelete).index; deleteNode(segmentTree, BBox[index].MinD(1), BBox[index].MaxD(1)); iterateDelete++; } while ((iterateInsert!=insertMBR.end())&& ((*iterateInsert).xVal == x)) { //insert segments from tree at position x int index = (*iterateInsert).index; insertNode(segmentTree, BBox[index].MinD(1), BBox[index].MaxD(1)); iterateInsert++; } cover += (segmentTree->measure) * (*xValiter - x); x = *xValiter; xValiter++; } deleteSegTree(segmentTree); return cover; } /* sweep line algorithm with segment tree only for dimension 2 */ template double getSweepAreas(vector< Rectangle > BBox) { if (dim<=1) return 0.0; //no Area available if (dim==2) return getSweepAreas2D(BBox); //2D-Sweepline //SweepLine with Quadtree is only for dim>2 if (BBox.size()<1) return 0.0; //area of empty rectangle is 0 unsigned int it = 0; //remove rectangles with size=0 (e.g. points/lines) bool zero = false; while (it xVals[dim-1]; set yVals; set zVals; multiset insertMBR[dim-1]; multiset deleteMBR[dim-1]; multiset::iterator iterateInsert[dim-1]; multiset::iterator iterateDelete[dim-1]; for (unsigned int i=0; i::iterator xValiter[dim-1]; double coversweep[dim]; for (unsigned int j=0; j xindex[dim-1]; unsigned int di; bool again; set::iterator indexIter; //initialization of the lists for (unsigned int j=0; j int index = (*iterateInsert[j]).index; xindex[j].insert(index); iterateInsert[j]++; } } xValiter[dim-3] = xVals[dim-3].begin(); iterateInsert[dim-3] = insertMBR[dim-3].begin(); iterateDelete[dim-3] = deleteMBR[dim-3].begin(); x[dim-3] = *xValiter[dim-3]; xValiter[dim-3]++; while (xValiter[0] != xVals[0].end()) //sweep "hypearea" for the values of all dimensions except the last two { while ((iterateDelete[dim-3]!=deleteMBR[dim-3].end())&& ((*iterateDelete[dim-3]).xVal == x[dim-3])) { //delete rectangles from tree at position int index = (*iterateDelete[dim-3]).index; xindex[dim-3].erase(index); iterateDelete[dim-3]++; bool all = true; for (unsigned int j=0; j int index = (*iterateInsert[dim-3]).index; xindex[dim-3].insert(index); iterateInsert[dim-3]++; bool all = true; for (unsigned int j=0; jmeasure); di = dim-3; again = true; while (again) { //set "sweepline" to next position coversweep[di] += coversweep[di+1] * (*xValiter[di] - x[di]); coversweep[di+1] = 0.0; x[di] = *xValiter[di]; xValiter[di]++; again = false; if ((xValiter[di] == xVals[di].end())&&(di>0)) { if (di==dim-3) { //clear the tree from resting rectangles... while ((iterateDelete[di]!=deleteMBR[di].end())&& ((*iterateDelete[di]).xVal == x[di])) { int index = (*iterateDelete[di]).index; xindex[di].erase(index); iterateDelete[di]++; bool all = true; for (unsigned int j=0; j int index = (*iterateDelete[di]).index; xindex[di].erase(index); iterateDelete[di]++; } while ((di!=dim-3)&& (iterateInsert[di]!=insertMBR[di].end())&& ((*iterateInsert[di]).xVal == x[di])) { //insert index of valid rectangles at position int index = (*iterateInsert[di]).index; xindex[di].insert(index); iterateInsert[di]++; } di--; } } deleteQuadTree(quadTreeYZ); return coversweep[0]; } /* sweep line algorithm with quad tree for dimensions $ >$ 2 ...and finally: Value mapping for operator ~getNodeInfo~: */ template int RTreeGetNodeInfoVM( Word* args, Word& result, int message, Word& local, Supplier s ) { GetSonsInfo* gsi; switch( message ) { case OPEN: { int nodeId = ((CcInt*)args[1].addr)->GetIntval(); R_Tree* tree = (R_Tree*) args[0].addr; if (checkRecordId(tree, nodeId)) { int maxIntEntries = tree->MaxEntries(0); int maxLeafEntries = tree->MaxEntries(tree->Height()); int maxEntr = maxIntEntries > maxLeafEntries ? maxIntEntries : maxLeafEntries;//needed to properly read the node. R_TreeNode* f = new R_TreeNode (false, 0, maxEntr); tree->GetNode(nodeId, *f); int m = f->EntryCount(); bool isRootNode = (nodeId==static_cast(tree->RootRecordId())); gsi = new GetSonsInfo(-1, m, f, new TupleType (nl->Second(GetTupleResultType(s))), nodeId, isRootNode); local.setAddr(gsi); } else local.setAddr(0); return 0; } case REQUEST : { if(local.addr == NULL) { return CANCEL; } gsi = (GetSonsInfo*)local.addr; if (gsi->index == gsi->maxEntries) { return CANCEL; } double MBRsize = (gsi->father->BoundingBox()).Area(); int numSons = gsi->father->IsLeaf()? 0 : gsi->maxEntries; double MBRdead = 0.0; vector< Rectangle > sonBB; //vector of BoundingBoxes of sons for (int i=0; imaxEntries; i++) { sonBB.push_back(gsi->father->BoundingBox(i)); } MBRdead = MBRsize - getSweepAreas(sonBB); int MBRoverlapsNo = 0; double MBRoverlapSize = 0.0; sonBB.clear(); for (int i=0; imaxEntries-1; i++) { for (int j= i+1; jmaxEntries; j++) { //if intersection between sonMBR_i and sonMBR_j if ((gsi->father->BoundingBox(i)).Intersects( gsi->father->BoundingBox(j))) { MBRoverlapsNo++; //count the overlappings //and build a vector of the overlapped MBRs sonBB.push_back((gsi->father->BoundingBox(i)).Intersection( gsi->father->BoundingBox(j))); } } } MBRoverlapSize = getSweepAreas(sonBB); //get size of overlapped MBRs double MBRdensity = gsi->maxEntries / MBRsize; Tuple *tuple = new Tuple( gsi->ttype ); tuple->PutAttribute(0, new CcInt(true, gsi->nodeId)); tuple->PutAttribute(1, new Rectangle(gsi->father->BoundingBox())); tuple->PutAttribute(2, new CcInt(true, numSons)); tuple->PutAttribute(3, new CcBool(true, gsi->father->IsLeaf())); tuple->PutAttribute(4, new CcBool(true, gsi->IsRoot)); tuple->PutAttribute(5, new CcReal(true, MBRsize)); tuple->PutAttribute(6, new CcReal(true, MBRdead)); tuple->PutAttribute(7, new CcReal(true, MBRoverlapSize)); tuple->PutAttribute(8, new CcInt(true, MBRoverlapsNo)); tuple->PutAttribute(9, new CcReal(true, MBRdensity)); result.setAddr(tuple); gsi->index = gsi->maxEntries; return YIELD; } case CLOSE : { if(local.addr) { gsi = (GetSonsInfo*)local.addr; delete gsi->father; gsi->ttype->DeleteIfAllowed(); delete gsi; local.setAddr(Address(0)); } return 0; } } // end switch cout << "RTreeGetNodeInfoVM(): Received UNKNOWN message!" << endl; return 0; } /* 5.13.3 Specification for Operator ~getNodeInfo~ */ const string RTreeGetNodeInfoSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" " "\"Example\" \"Comment\" ) " "((rtree (tuple ((x1 t1)...(xn tn))) ti false) x int" "-> stream(tuple((NodeId int) (MBR rect) (NoOfSons int) \n" " (IsLeafNode bool) (IsRootNode bool) \n" " (MBRsize real) (MBRdead real) (MBRoverlapSize real) \n" " (MBRoverlapsNo int) (MBRdensity real)))" "getNodeInfo( _ , _ )" "This operator allows introspection of an RTree. It creates a " "stream of a tuple, which describes one node of the R-Tree." "query getNodeInfo(strassen_geoData_rtree, 2);" "Stream is empty, if given record no is not existing." ") )"; /* 5.13.4 Selection Function for Operator ~getNodeInfo~ The selection function is used for the operators ~getNodeInfo~, ~getNodeSons~ and ~getLeafEntries~. */ int RTreeGetInfoTypeSelect (ListExpr args) { AlgebraManager *algMgr = SecondoSystem::GetAlgebraManager(); ListExpr errorInfo = nl->OneElemList( nl->SymbolAtom( "ERRORS" ) ); string rtreeDescriptionStr; /* handle rtree part of argument */ ListExpr rtreeDescription = nl->First(args); ListExpr rtreeKeyType = nl->Third(rtreeDescription); if( nl->IsEqual(rtreeKeyType, Rectangle<2>::BasicType()) || algMgr->CheckKind(Kind::SPATIAL2D(), rtreeKeyType, errorInfo)) return 0; else if( nl->IsEqual(rtreeKeyType, Rectangle<3>::BasicType()) || algMgr->CheckKind(Kind::SPATIAL3D(), rtreeKeyType, errorInfo)) return 1; else if( nl->IsEqual(rtreeKeyType, Rectangle<4>::BasicType()) || algMgr->CheckKind(Kind::SPATIAL4D(), rtreeKeyType, errorInfo)) return 2; else if( nl->IsEqual(rtreeKeyType, Rectangle<8>::BasicType()) || algMgr->CheckKind(Kind::SPATIAL8D(), rtreeKeyType, errorInfo)) return 3; else if( nl->IsEqual(rtreeKeyType, Rectangle<1>::BasicType()) || algMgr->CheckKind(Kind::SPATIAL1D(), rtreeKeyType, errorInfo)) return 4; return -1; } ValueMapping RTreeGetNodeInfo [] = { RTreeGetNodeInfoVM<2>, RTreeGetNodeInfoVM<3>, RTreeGetNodeInfoVM<4>, RTreeGetNodeInfoVM<8>, RTreeGetNodeInfoVM<1>}; /* 5.13.5 Definition of Operator ~getNodeInfo~ */ Operator rtreegetnodeinfo( "getNodeInfo", // name RTreeGetNodeInfoSpec, // specification 5, RTreeGetNodeInfo, // value mapping RTreeGetInfoTypeSelect, // selection function RTreeGetInfoTypeTypeMap // type mapping ); /* 5.14 Operator ~getNodeSons~ This operator allows introspection of an R-tree. It creates a stream of tuples, each describe a son node of the node with the specified record no. The stream is empty, if the given recordnumber is not existing/not valid. Signature is ---- getNodeSons: (rtree) x int --> stream(tuple((NodeId int) (SonId int) (SonMBR rect))) ---- */ /* 5.14.1 TypeMapping for Operator ~getNodeSons~ The typemapping function is the one of the operator ~getNodeInfo~ and uses a template parameter InfoType to differ between the typemapping of the operators ~getNodeInfo~, ~getNodeSons~ and ~getLeafEntries~. The typemapping of operator ~getNodeSons~ uses InfoType = NODESONS. */ /* 5.14.2 Value Mapping for Operator ~getNodeSons~ */ template int RTreeGetNodeSonsVM( Word* args, Word& result, int message, Word& local, Supplier s ) { GetSonsInfo* gsi; switch( message ) { case OPEN: { int nodeId = ((CcInt*)args[1].addr)->GetIntval(); R_Tree* tree = (R_Tree*) args[0].addr; if (checkRecordId(tree, nodeId)) { int maxIntEntries = tree->MaxEntries(0); int maxLeafEntries = tree->MaxEntries(tree->Height()); int maxEntr = maxIntEntries > maxLeafEntries ? maxIntEntries : maxLeafEntries;//needed to properly read the node. R_TreeNode* f = new R_TreeNode (false, 0, maxEntr); tree->GetNode(nodeId, *f); int m = f->EntryCount(); bool isRootNode = (nodeId==static_cast(tree->RootRecordId())); gsi = new GetSonsInfo(0, m, f, new TupleType (nl->Second(GetTupleResultType(s))), nodeId, isRootNode); local.setAddr(gsi); } else local.setAddr(0); return 0; } case REQUEST : { if(local.addr == NULL) { return CANCEL; } gsi = (GetSonsInfo*)local.addr; if (gsi->index == gsi->maxEntries) { return CANCEL; } if (gsi->father->IsLeaf()) { Tuple *tuple = new Tuple( gsi->ttype ); tuple->PutAttribute(0, new CcInt(true, gsi->nodeId)); tuple->PutAttribute(1, new CcInt(false, 0)); tuple->PutAttribute(2, new Rectangle(false)); result.setAddr(tuple); gsi->index = gsi->maxEntries; /* ensures that CANCEL will be returned at next call. */ return YIELD; } Tuple *tuple = new Tuple( gsi->ttype ); tuple->PutAttribute(0, new CcInt(true, gsi->nodeId)); R_TreeInternalEntry* son = gsi->father-> GetInternalEntry(gsi->index); tuple->PutAttribute(1, new CcInt(true, son->pointer)); tuple->PutAttribute(2, new Rectangle(son->box)); result.setAddr(tuple); gsi->index++; return YIELD; } case CLOSE : { if(local.addr) { gsi = (GetSonsInfo*)local.addr; delete gsi->father; gsi->ttype->DeleteIfAllowed(); delete gsi; local.setAddr(Address(0)); } return 0; } } // end switch cout << "RTreeGetNodeSonsVM(): Received UNKNOWN message!" << endl; return 0; } /* 5.14.3 Specification for Operator ~getNodeSons~ */ const string RTreeGetNodeSonsSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" " "\"Example\" \"Comment\" ) " "((rtree (tuple ((x1 t1)...(xn tn))) ti false) x int " "-> stream(tuple((NodeId int) (SonId int) (SonMBR rect)))" "getNodeSons( _ , _ )" "This operator allows introspection of an RTree. It creates a " "stream of tuples, each describe a " "son node of the node with the specified record no." "query getNodeSons(strassen_geodata_rtree, 2);" "Stream is empty, if given record no is not existing." ") )"; /* 5.14.4 Selection Function for Operator ~getNodeSons~ The selection function is the one of the operator ~getNodeInfo~. */ ValueMapping RTreeGetNodeSons [] = { RTreeGetNodeSonsVM<2>, // 0 RTreeGetNodeSonsVM<3>, // 1 RTreeGetNodeSonsVM<4>, // 2 RTreeGetNodeSonsVM<8> // 3 }; /* 5.14.5 Definition of Operator ~getNodeSons~ */ Operator rtreegetnodesons( "getNodeSons", // name RTreeGetNodeSonsSpec, // specification 4, RTreeGetNodeSons, // value mapping RTreeGetInfoTypeSelect, // selection function RTreeGetInfoTypeTypeMap // type mapping ); /* 5.14 Operator ~getLeafEntries~ This operator allows introspection of an R-tree. It creates a stream of tuples, each describe an entry of the leafnode with the specified record no. The entries of the leafnode are tupleidentifiers (tid). The stream is empty, if the given recordnumber is not existing/not valid or the specified node is not a leafnode. Signature is ---- getLeafEntries: (rtree) x int --> stream(tuple((NodeId int) (TupleID tid))) (EntryMBR rect))) ---- */ /* 5.14.1 TypeMapping for Operator ~getLeafEntries~ The typemapping function is the one of the operator ~getNodeInfo~ and uses a template parameter InfoType to differ between the typemapping of the operators ~getNodeInfo~, ~getNodeSons~ and ~getLeafEntries~. The typemapping of operator ~getLeafEntries~ uses InfoType = LEAFENTRIES. */ /* 5.14.2 Value Mapping for Operator ~getLeafEntries~ */ template int RTreeGetLeafEntriesVM( Word* args, Word& result, int message, Word& local, Supplier s ) { GetSonsInfo* gsi; switch( message ) { case OPEN: { int nodeId = ((CcInt*)args[1].addr)->GetIntval(); R_Tree* tree = (R_Tree*) args[0].addr; if (checkRecordId(tree, nodeId)) { int maxIntEntries = tree->MaxEntries(0); int maxLeafEntries = tree->MaxEntries(tree->Height()); int maxEntr = maxIntEntries > maxLeafEntries ? maxIntEntries : maxLeafEntries;//needed to properly read the node. R_TreeNode* f = new R_TreeNode (false, 0, maxEntr); tree->GetNode(nodeId, *f); int m = f->EntryCount(); bool isRootNode = (nodeId==static_cast(tree->RootRecordId())); gsi = new GetSonsInfo(0, m, f, new TupleType (nl->Second(GetTupleResultType(s))), nodeId, isRootNode); local.setAddr(gsi); } else local.setAddr(0); return 0; } case REQUEST : { if(local.addr == NULL) { return CANCEL; } gsi = (GetSonsInfo*)local.addr; if (gsi->index == gsi->maxEntries) { return CANCEL; } if (!(gsi->father->IsLeaf())) { return CANCEL; } Tuple *tuple = new Tuple( gsi->ttype ); tuple->PutAttribute(0, new CcInt(true, gsi->nodeId)); R_TreeLeafEntry* entry = gsi->father-> GetLeafEntry(gsi->index); tuple->PutAttribute(1, new TupleIdentifier(true, entry->info)); tuple->PutAttribute(2, new Rectangle(entry->box)); result.setAddr(tuple); gsi->index++; return YIELD; } case CLOSE : { if(local.addr) { gsi = (GetSonsInfo*)local.addr; delete gsi->father; gsi->ttype->DeleteIfAllowed(); delete gsi; local.setAddr(Address(0)); } return 0; } } // end switch cout << "RTreeGetLeafEntriesVM(): Received UNKNOWN message!" << endl; return 0; } /* 5.14.3 Specification for Operator ~getLeafEntries~ */ const string RTreeGetLeafEntriesSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" " "\"Example\" \"Comment\" ) " "((rtree (tuple ((x1 t1)...(xn tn))) ti false) x int " "-> stream(tuple((NodeId int)(TupleID tid)(EntryMBR rect)))" "getLeafEntries( _ , _ )" "This operator allows introspection of an RTree. It creates a " "stream of tupleids, each describe an entry " "of the leafnode with the specified record no." "query getLeafEntries(strassen_geodata_rtree, 2);" "Stream is empty, if given record no is not existing." ") )"; /* 5.14.4 Selection Function for Operator ~getLeafEntries~ The selection function is the one of the operator ~getNodeInfo~. */ ValueMapping RTreeGetLeafEntries [] = { RTreeGetLeafEntriesVM<2>, // 0 RTreeGetLeafEntriesVM<3>, // 1 RTreeGetLeafEntriesVM<4>, // 2 RTreeGetLeafEntriesVM<8> // 3 }; /* 5.14.5 Definition of Operator ~getLeafEntries~ */ Operator rtreegetleafentries( "getLeafEntries", // name RTreeGetLeafEntriesSpec, // specification 4, RTreeGetLeafEntries, // value mapping RTreeGetInfoTypeSelect, // selection function RTreeGetInfoTypeTypeMap // type mapping ); /* 5.16 Operator ~SpatialJoin~ This operator gets two rtrees and returns such pairs of tuple id's with intersecting bounding boxes. 5.16.1 Type Mapping Signature is rtree [x] rtree -> stream(tuple([TID1 : tid, TID2 : tid])) */ ListExpr dspatialJoinTM(ListExpr args){ string err = "rtree x rel x rtree x rel [ x renaming] expected"; int len = nl->ListLength(args); if(len!=4 && len!=5){ return listutils::typeError(err); } // check r-trees ListExpr tree1 = nl->First(args); ListExpr tree2 = nl->Third(args); if(!listutils::isRTreeDescription(tree1) || !listutils::isRTreeDescription(tree2)){ return listutils::typeError(err); } if(!nl->Equal(nl->First(tree1) , nl->First(tree2))){ return listutils::typeError("Rtree with different dimensions found"); } if(!nl->Equal(nl->Fourth(tree1) , nl->Fourth(tree2))){ return listutils::typeError("One of the rtrees supports double indexing"); } if(nl->BoolValue(nl->Fourth(tree1))){ return listutils::typeError("double indexing is not allowed here"); } // check relations ListExpr rel1 = nl->Second(args); ListExpr rel2 = nl->Fourth(args); if(!Relation::checkType(rel1) || !Relation::checkType(rel2)){ return listutils::typeError("One of the rtrees supports double indexing"); } ListExpr al1 = nl->Second(nl->Second(rel1)); ListExpr al2 = nl->Second(nl->Second(rel2)); ListExpr attrList; if(len==4){ attrList = listutils::concat(al1,al2); } else { ListExpr ren = nl->Fifth(args); if(!listutils::isSymbol(ren)){ return listutils::typeError(err); } string renaming = "_" + nl->SymbolValue(ren); ListExpr ral2=nl->TheEmptyList(); ListExpr last=nl->TheEmptyList(); bool first = true; while(!nl->IsEmpty(al2)){ ListExpr f = nl->First(al2); al2 = nl->Rest(al2); ListExpr nf = nl->TwoElemList( nl->SymbolAtom( nl->SymbolValue(nl->First(f)) +renaming), nl->Second(f)); if(first){ ral2 = nl->OneElemList(nf); last = ral2; first = false; } else { last = nl->Append(last,nf); } } attrList = listutils::concat(al1,ral2); } if(!listutils::isAttrList(attrList)){ return listutils::typeError("Name conflicts in resulting tuple"); } return nl->TwoElemList( nl->SymbolAtom(Stream::BasicType()), nl->TwoElemList( nl->SymbolAtom(Tuple::BasicType()), attrList)); } /* LocalInfo class for directSpatialJoin */ template class DspatialJoinLocal{ public: DspatialJoinLocal(R_Tree* _r1, GenericRelation* _rel1, R_Tree* _r2, GenericRelation* _rel2, ListExpr ttl, size_t maxMem): r1(_r1), r2(_r2), rel1(_rel1), rel2(_rel2), tt(0), q_ii(), q_il(), q_li(), q_ll(){ tt = new TupleType(ttl); R_TreeNode n1 = r1->Root(); R_TreeNode n2 = r2->Root(); processNodes(n1,n2); max1 = max(r1->MaxLeafEntries(), r1->MaxInternalEntries()); max2 = max(r2->MaxLeafEntries(), r2->MaxInternalEntries()); // compute size for storing the stacks size_t s_q_ii = max1*max2 * min(r1->Height(), r2->Height()); size_t s_q_li = max1*max2 * abs(r1->Height() - r2->Height()); // s_q_li covers also s_q_il size_t s_q_ll = max1*max2; size_t sizes = (s_q_ii + s_q_li) * sizeof(R_TreeInternalEntry) + s_q_ll * sizeof(pair); if(sizes>maxMem){ maxMem = 0; } else { maxMem = maxMem - sizes; } if((rel1->GetNoTuples()>0) && (rel2->GetNoTuples()>0)){ // compute amount of tuples to be stored within caches // following the rules: // 1. tupleNumber1 * tupleSize1 + tupleNumber2 * TupleSize2 = maxMem // 2. tupleNumber1 / tupleNumber2 = tupleCount1 / tupleCount2 // cond. 1 ensures that the memory is sufficient to store the tuples // cond. 2 distributes the available memory according to the number // of tuples within the relations int tupleSize1 = (int) floor(rel1->GetTotalExtSize() / rel1->GetNoTuples()); int tupleSize2 = (int) floor(rel2->GetTotalExtSize() / rel2->GetNoTuples()); int tupleCount1 = rel1->GetNoTuples(); int tupleCount2 = rel2->GetNoTuples(); size_t tmp = tupleSize1 + (tupleSize2*tupleCount2)/tupleCount1; size_t noTuples1 = maxMem / tmp; size_t noTuples2 = (tupleCount2*noTuples1)/tupleCount1; // force caches of minimum size 5 if(noTuples1 < 5){ noTuples1 = 5; } if(noTuples2 < 5){ noTuples2 = 5; } lru1 = new LRU(noTuples1); lru2 = new LRU(noTuples2); } else { // at least one of the relations is empty // avoid crash if using rtree not fit to the relations // so, just create empty caches lru1 = new LRU(3); lru2 = new LRU(3); } } ~DspatialJoinLocal(){ tt->DeleteIfAllowed(); // cache statistics // cout << "Cache1 : " << endl; // lru1->printStats(cout); // cout << endl << "Cache 2 : " << endl; // lru2->printStats(cout); // cout << endl; // remove elements from LRU while(!lru1->empty()){ LRUEntry* victim = lru1->deleteLast(); victim->value->DeleteIfAllowed(); delete victim; } while(!lru2->empty()){ LRUEntry* victim = lru2->deleteLast(); victim->value->DeleteIfAllowed(); delete victim; } delete lru1; delete lru2; } Tuple* nextTuple(){ Tuple* res = getRes(); if(res != 0) { return res; } while(!allempty()){ if(!processIL()){ if(!processLI()){ processII(); } } res = getRes(); if(res){ return res; } } return 0; } private: R_Tree* r1; R_Tree* r2; GenericRelation* rel1; GenericRelation* rel2; TupleType* tt; std::stack< pair, R_TreeInternalEntry > > q_ii; std::stack< pair, R_TreeLeafEntry > > q_il; std::stack< pair, R_TreeInternalEntry > > q_li; std::queue< pair > q_ll; int max1; int max2; LRU* lru1; LRU* lru2; bool allempty() const{ return q_ll.empty() && q_li.empty() && q_il.empty() && q_ii.empty(); } void processNodes(const R_TreeNode & n1, const R_TreeNode & n2){ bool l1 = n1.IsLeaf(); bool l2 = n2.IsLeaf(); if(l1 && l2){ processLeafLeaf(n1,n2); } else if (l1 && !l1){ processLeafInner(n1,n2); } else if (!l1 && l2){ processInnerLeaf(n1,n2); } else { processInnerInner(n1,n2); } } void printStats(){ cout << " q_ii : " << q_ii.size() << " elements" << endl; cout << " q_il : " << q_il.size() << " elements" << endl; cout << " q_li : " << q_li.size() << " elements" << endl; cout << " q_ll : " << q_ll.size() << " elements" << endl; } /* Converts an element in q[_]ll into a result tuple. */ Tuple* getRes(){ while(!q_ll.empty()){ pair p = q_ll.front(); q_ll.pop(); Tuple* t1 = getTuple1(p.first); if(t1){ Tuple* t2 = getTuple2(p.second); if(t2){ Tuple* res = new Tuple(tt); Concat(t1,t2,res); return res; } t1->DeleteIfAllowed(); } } return 0; } Tuple* getTuple1(const TupleId id){ Tuple** t = lru1->get(id); if(t){ return *t; } Tuple* t1 = rel1->GetTuple(id,true); if(!t1){ return 0; } // insert into lru LRUEntry* victim = lru1->use(id,t1); if(victim){ victim->value->DeleteIfAllowed(); delete victim; } return t1; } Tuple* getTuple2(const TupleId id){ Tuple** t = lru2->get(id); if(t){ return *t; } Tuple* t1 = rel2->GetTuple(id,true); if(!t1){ return 0; } // insert into lru LRUEntry* victim = lru2->use(id,t1); if(victim){ victim->value->DeleteIfAllowed(); delete victim; } return t1; } /* Processes two leaf nodes */ void processLeafLeaf( const R_TreeNode & n1, const R_TreeNode & n2){ for(int i1=0; i1 < n1.EntryCount(); i1++){ R_TreeLeafEntry* e1 = n1.GetLeafEntry(i1); for(int i2=0;i2 < n2.EntryCount(); i2++){ R_TreeLeafEntry* e2 = n2.GetLeafEntry(i2); if(e1->box.Intersects(e2->box)){ pair p(e1->info, e2->info); q_ll.push(p); } } } } void processLeafInner( const R_TreeNode & n1, const R_TreeNode & n2){ for(int i1=0; i1 < n1.EntryCount(); i1++){ R_TreeLeafEntry e1 = *n1.GetLeafEntry(i1); for(int i2=0;i2 < n2.EntryCount(); i2++){ R_TreeInternalEntry e2 = *n2.GetInternalEntry(i2); if(e1.box.Intersects(e2.box)){ pair< R_TreeLeafEntry, R_TreeInternalEntry > p(e1,e2); q_li.push(p); } } } } void processInnerLeaf( const R_TreeNode & n1, const R_TreeNode & n2){ for(int i1=0; i1 < n1.EntryCount(); i1++){ R_TreeInternalEntry e1 = *n1.GetInternalEntry(i1); for(int i2=0;i2 < n2.EntryCount(); i2++){ R_TreeLeafEntry e2 = *n2.GetLeafEntry(i2); if(e1.box.Intersects(e2.box)){ pair, R_TreeLeafEntry > p(e1,e2); q_il.push(p); } } } } void processInnerInner( const R_TreeNode & n1, const R_TreeNode & n2){ for(int i1=0; i1 < n1.EntryCount(); i1++){ R_TreeInternalEntry e1 = *n1.GetInternalEntry(i1); for(int i2=0;i2 < n2.EntryCount(); i2++){ R_TreeInternalEntry e2 = *n2.GetInternalEntry(i2); if(e1.box.Intersects(e2.box)){ pair, R_TreeInternalEntry > p(e1,e2); q_ii.push(p); } } } } bool processIL(){ if(q_il.empty()){ return false; } pair, R_TreeLeafEntry > p = q_il.top(); q_il.pop(); R_TreeNode n1(true,1,max1); r1->GetNode(p.first.pointer,n1); if(n1.IsLeaf()){ for(int i1=0;i1 e1 = *n1.GetLeafEntry(i1); if(p.second.box.Intersects(e1.box)){ pair pn(e1.info, p.second.info); q_ll.push(pn); } } } else { for(int i1=0;i1 e1 = *n1.GetInternalEntry(i1); if(p.second.box.Intersects(e1.box)){ pair, R_TreeLeafEntry > pn(e1, p.second); q_il.push(pn); } } } return true; } bool processLI(){ if(q_li.empty()){ return false; } pair, R_TreeInternalEntry > p = q_li.top(); q_li.pop(); R_TreeNode n2(true,1,max2); r2->GetNode(p.second.pointer,n2); if(n2.IsLeaf()){ for(int i2=0;i2 e2 = *n2.GetLeafEntry(i2); if(p.first.box.Intersects(e2.box)){ pair pn(p.first.info, e2.info); q_ll.push(pn); } } } else { for(int i2=0;i2 e2 = *n2.GetInternalEntry(i2); if(p.first.box.Intersects(e2.box)){ pair, R_TreeInternalEntry > pn(p.first, e2); q_li.push(pn); } } } return true; } bool processII(){ if(q_ii.empty()){ return false; } pair, R_TreeInternalEntry > p = q_ii.top(); q_ii.pop(); R_TreeNode n1(true,1,max1); R_TreeNode n2(true,1,max2); r1->GetNode(p.first.pointer, n1); r2->GetNode(p.second.pointer, n2); processNodes(n1,n2); return true; } }; template int dspatialJoinVM1(Word* args, Word& result, int message, Word& local, Supplier s){ DspatialJoinLocal* li = (DspatialJoinLocal*) local.addr; switch(message){ case OPEN: { if(li){ delete li; } ListExpr ttl = nl->Second(GetTupleResultType(s)); R_Tree* r1 = (R_Tree*) args[0].addr; GenericRelation* rel1 = (GenericRelation*) args[1].addr; R_Tree* r2 = (R_Tree*) args[2].addr; GenericRelation* rel2 = (GenericRelation*) args[3].addr; int maxMem = qp->GetMemorySize(s) * 1024 * 1024; local.addr = new DspatialJoinLocal(r1,rel1, r2,rel2, ttl, maxMem); return 0; } case REQUEST: { if(!li){ result.addr=0; return CANCEL; } result.addr = li->nextTuple(); return result.addr?YIELD:CANCEL; } case CLOSE: { if(li){ delete li; local.addr =0; } return 0; } } return -1; } /* 5.16.3 ValueMapping array */ ValueMapping dspatialJoinVM[] = { dspatialJoinVM1<2>, dspatialJoinVM1<3>, dspatialJoinVM1<4>, dspatialJoinVM1<8> }; /* 5.16.4 Selection Function */ int dspatialJoinSelect(ListExpr args){ int d = listutils::getRTreeDim(nl->First(args)); switch(d){ case 2 : return 0; case 3 : return 1; case 4 : return 2; case 8 : return 3; default : return -1; } } /* 5.16..5 Operator Spec */ const string dspatialJoinSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" " "\"Example\" \"Comment\" ) " "( rtree x rtree -> stream(tuple([TID1 : tid, TID2 : tid]))" "" " _ _ dspatialJoin " "This operator returns such pairs of tuple id's " "having overlapping bounding boxes within the rtrees" "." "query strassen_geoData_rtree " "strassen_geoData_rtree dspatialJoin count" "" ") )"; /* 5.16.6 Operator instance */ Operator dspatialJoin( "dspatialJoin", // name dspatialJoinSpec, // specification 4, dspatialJoinVM, // value mapping dspatialJoinSelect, // selection function dspatialJoinTM // type mapping ); /* 6 Definition and initialization of RTree Algebra */ class RTreeAlgebra : public Algebra { public: RTreeAlgebra() : Algebra() { AddTypeConstructor( &rtree1 ); AddTypeConstructor( &rtree ); AddTypeConstructor( &rtree3 ); AddTypeConstructor( &rtree4 ); AddTypeConstructor( &rtree8 ); AddOperator( &creatertree ); AddOperator( &bulkloadrtree ); AddOperator( &windowintersects ); AddOperator( &windowintersectsS ); AddOperator( &gettuples ); AddOperator( &gettuplesdbl ); AddOperator( &gettuples2 ); AddOperator( &rtreenodes ); AddOperator( &rtreetreeheight ); AddOperator( &rtreenoofnodes ); AddOperator( &rtreenoofentries ); AddOperator( &rtreebbox ); AddOperator( &rtreeentries); AddOperator( &getfileinfortree); AddOperator( &updatebulkloadrtree); AddOperator( &rtreegetrootnode ); AddOperator( &rtreegetnodeinfo ); AddOperator( &rtreegetnodesons ); AddOperator( &rtreegetleafentries ); AddOperator(&dspatialJoin); dspatialJoin.SetUsesMemory(); #ifdef USE_PROGRESS windowintersects.EnableProgress(); windowintersectsS.EnableProgress(); gettuples.EnableProgress(); gettuples2.EnableProgress(); #endif } ~RTreeAlgebra() {}; }; extern "C" Algebra* InitializeRTreeAlgebra( NestedList* nlRef, QueryProcessor* qpRef ) { nl = nlRef; qp = qpRef; return (new RTreeAlgebra); }