/* ---- This file is part of SECONDO. Copyright (C) 2011, 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 ---- //[_] [\_] */ #include #include "Algebras/MMRTree/MMRTreeAlgebra.h" #include "RIndex.h" #include "Algebra.h" #include "NestedList.h" #include "QueryProcessor.h" #include "Stream.h" #include "ListUtils.h" #include "Algebras/Relation-C++/RelationAlgebra.h" #include "Algebras/TupleIdentifier/TupleIdentifier.h" #include "Algebras/FText/FTextAlgebra.h" extern NestedList* nl; extern QueryProcessor* qp; using namespace std; /* 1 RIndexAlgebra This algebra is used to test performance of a new index structure for a set of rectangles realized in main memory. This structure is compared with an main memory R-tree implementation. */ /* 1.1 Operator ~insertRIndex~ This operator tests the performance of insertions into the RIndex structure. It takes a stream of rectangles and inserts them into an RIndex. Each rectangle is put into the result stream without changes. 1.1.1 Type Mapping The signature is: stream(rect) -> stream(rect) */ ListExpr insertRindexTM(ListExpr args){ if(!nl->HasLength(args,1)){ return listutils::typeError("stream(rect) expected"); } if(Stream >::checkType(nl->First(args))){ return nl->First(args); } return listutils::typeError("stream(rectangle) expected"); }; /* 1.1.2 ValueMapping We use the Rindex as localinfo. If the stream is closed, the index is deleted without using it. */ int insertRindexVM( Word* args, Word& result, int message, Word& local, Supplier s ) { static int c = 0; RIndex<2,int>* rindex = static_cast*>(local.addr); switch(message){ case OPEN: { qp->Open(args[0].addr); if(rindex){ delete rindex; } local.setAddr(new RIndex<2,int>()); return 0; } case REQUEST: { Word w; qp->Request(args[0].addr, w); if(qp->Received(args[0].addr)){ result = w; Rectangle<2>* r = (Rectangle<2>*) w.addr; if(rindex){ rindex->insert(*r,c++); } return YIELD; } else { return CANCEL; } } case CLOSE: { qp->Close(args[0].addr); if(rindex){ delete rindex; } local.setAddr(0); return 0; } }; assert(false); return -1; } /* 1.1.3 Specification */ const string insertRindexSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" )" "( stream(rectangle) -> stream(rectangle) " "_ insertRindex" "Inserts all the rectangles within the " "stream into an Rindex" "" "query strassen feed extend[B : bbox(.geoData)] insertRindexi[B] count" "" ") )"; /* 1.1.4 Operator instance */ Operator insertRindex ( "insertRindex", insertRindexSpec, insertRindexVM, Operator::SimpleSelect, insertRindexTM); /* 1.2 Operator ~findRIndex~ This operator builds an RIndex from the rectangles coming out of a tuple stream. The tuples are removed after extracting the rectangle. When the tuple stream is exhausted, a single search is performed on the created RIndex using a rectangle given as the second parameter. The tupleIds of the tuples with intersecting rectangles are returned in the result stream. 1.2.1 Type Mapping The Signature is: stream(tuple(A)) x a[_]j x rect -> stream(tid) where a[_]j is an attribute name in A of type rect. */ ListExpr findRindexTM(ListExpr args){ string err = "stream(tuple( (..)...(a_i rect) ...)) x a_i x rect expected"; if(!nl->HasLength(args,3)){ return listutils::typeError(err + "..1"); } if(!Stream::checkType(nl->First(args))){ return listutils::typeError(err); } if(!listutils::isSymbol(nl->Second(args))){ return listutils::typeError(err + "..2"); } if(!Rect::checkType(nl->Third(args))){ return listutils::typeError(err + ".. 3"); } ListExpr attrList = nl->Second(nl->Second(nl->First(args))); ListExpr type; string name = nl->SymbolValue(nl->Second(args)); int index = listutils::findAttribute(attrList, name, type); if(index==0){ return listutils::typeError("Attribute " + name + " not found in tuple"); } return nl->ThreeElemList( nl->SymbolAtom(Symbols::APPEND()), nl->OneElemList(nl->IntAtom(index-1)), nl->TwoElemList(nl->SymbolAtom(Stream::BasicType()), nl->SymbolAtom(TupleIdentifier::BasicType()))); } /* 1.2.2 Value Mapping */ int findRindexVM( Word* args, Word& result, int message, Word& local, Supplier s ){ switch (message){ case OPEN : { if(local.addr){ delete (vector, TupleId> >*) local.addr; local.addr = 0; } RIndex<2,TupleId> index; Stream stream(args[0].addr); stream.open(); Tuple* tuple = stream.request(); int i = ((CcInt*)args[3].addr)->GetValue(); int c = 0; while(tuple){ c++; index.insert(*((Rect*)tuple->GetAttribute(i)), tuple->GetTupleId()); tuple->DeleteIfAllowed(); tuple = stream.request(); } stream.close(); vector, TupleId> >* res; res = new vector, TupleId> >(); Rectangle<2u>* r = (Rectangle<2u>*) args[2].addr; index.findSimple( *r, *res); local.addr = res; return 0; } case REQUEST: { if(!local.addr){ return CANCEL; } vector, TupleId> >* res; res = (vector, TupleId> >*) local.addr; if(res->empty()){ return CANCEL; } result.addr = new TupleIdentifier(true, res->back().second); res->pop_back(); return YIELD; } case CLOSE: { if(local.addr){ delete (vector, TupleId> >*) local.addr; local.addr = 0; } return 0; } } return -1; } /* 1.2.3 Specification */ const string findRindexSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" )" "( stream(tuple) x attrName x rect -> stream(tupleid) " "_ findRindex [_ , _ ] " "Includes the rectangles referenced by the " "attribute name into an Rindex," " After that, it searches on this structure using the " "rectangle and returns all" " tuple ids whose rectangles are intersecting" " the query rectangle " "query strassen feed extend[B : bbox(.geoData)] " "findRindex[B, [const rect value (-10 -10 10 10)] count " ") )"; /* 1.2.4 Operator instance */ Operator findRindex ( "findRindex", findRindexSpec, findRindexVM, Operator::SimpleSelect, findRindexTM); /* 1.3 Operator ~statRIndex~ This operator creates an RIndex from the rectangles stored within a tuple stream. After creating the index, some information about the structure are reported in the result (as text). 1.3.1 Type Mapping The signature is: stream(tuple(A)) x a[_]j -> text where a[_]j is an attribute name in A belonging to type rect. */ ListExpr statRindexTM(ListExpr args){ string err = "stream(tuple) x attrname expected"; int len = nl->ListLength(args); if((len!=2)){ return listutils::typeError(err); } if(!Stream::checkType(nl->First(args))){ return listutils::typeError(err); } ListExpr sec = nl->Second(args); if(!listutils::isSymbol(sec)){ return listutils::typeError(err); } ListExpr attrType; string name = nl->SymbolValue(sec); int index = listutils::findAttribute( nl->Second(nl->Second(nl->First(args))), name, attrType); if(index==0){ return listutils::typeError("Attribute " + name + " not known in stream"); } if(!Rectangle<2>::checkType(attrType) && !Rectangle<3>::checkType(attrType)){ return listutils::typeError("Attribute " + name + " not of type rect or rect3"); } return nl->ThreeElemList( nl->SymbolAtom(Symbols::APPEND()), nl->OneElemList(nl->IntAtom(index-1)), nl->SymbolAtom(FText::BasicType())); } /* 1.3.2 Value Mapping */ template int statRindexVM( Word* args, Word& result, int message, Word& local, Supplier s ){ Stream stream(args[0]); Rectangle* r; int index = ((CcInt*)args[2].addr)->GetValue(); stream.open(); Tuple* t; t = stream.request(); size_t tupleSizes = 0; RIndex ind; while(t){ r = (Rectangle*) t->GetAttribute(index); ind.insert(*r,1); tupleSizes += t->GetMemSize(); t->DeleteIfAllowed(); t = stream.request(); } stream.close(); result = qp->ResultStorage(s); FText* res = static_cast(result.addr); stringstream out; out << "countEntries =" << ind.countEntries() << endl; out << "height = " << ind.height() << endl; out << "noLeafs = " << ind.noLeafs() << endl; out << "dim0Entries = " << ind.dim0Entries() << endl; out << "dim0Leafs = " << ind.dim0Leafs() << endl; out << "maxBranches = " << ind.maxBranches() << endl; out << "branches = " << ind.branches() << endl; size_t um = ind.usedMem(); out << "usedMem() = " << ind.usedMem() << " (" << hMem(um) << ")" << endl; out << "used mem by tuples = " << tupleSizes << " (" << hMem(tupleSizes) << ")" << endl; res->Set(true,out.str()); return 0; } const string statRindexSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" )" "( stream(tuple(A)) x a_j -> text " " " "_ statRindex[_] " "Creates an RIndex from the rectangles referenced by a_j in A." "an returns statistical informations about this structure " "query strassen extend [B : bbox(.geoData)] feed statRIndex[B] " " " ") )"; int statRindexSelect(ListExpr args){ ListExpr attrList = nl->Second(nl->Second(nl->First(args))); string name = nl->SymbolValue(nl->Second(args)); ListExpr type; int index = listutils::findAttribute(attrList,name,type); assert(index >0); if(Rectangle<2>::checkType(type)){ return 0; } else if(Rectangle<3>::checkType(type)){ return 1; } return -1; } ValueMapping statRindexvm[] = { statRindexVM<2>, statRindexVM<3> }; Operator statRindex ( "statRindex", statRindexSpec, 2, statRindexvm, statRindexSelect, statRindexTM); /* 1.4 ~joinRIndex~ 1.4.1 Type Mapping Signature is: stream(tuple(A)) x stream(tuple(B)) x a[_]i x b[_]j -> stream(tuple((TID1 : tid)(TID2: tid))) where a[_]i points to a spatial attribute in A and b[_]j points to a spatial attribute in B. */ ListExpr joinRindexTM(ListExpr args){ string err = "stream(tuple(A)) x stream(tuple(B)) x a_i x b_j expected"; if(!nl->HasLength(args,4)){ return listutils::typeError(err); } if(!Stream::checkType(nl->First(args)) || !Stream::checkType(nl->Second(args)) || !listutils::isSymbol(nl->Third(args)) || !listutils::isSymbol(nl->Fourth(args))){ return listutils::typeError(err); } ListExpr attrList1 = nl->Second(nl->Second(nl->First(args))); ListExpr attrList2 = nl->Second(nl->Second(nl->Second(args))); string name1 = nl->SymbolValue(nl->Third(args)); string name2 = nl->SymbolValue(nl->Fourth(args)); ListExpr type1; ListExpr type2; int index1 = listutils::findAttribute(attrList1, name1, type1); if(index1 == 0){ return listutils::typeError("Attribute " + name1 + " not present in first stream"); } if(!listutils::isKind(type1, Kind::SPATIAL2D())){ return listutils::typeError("Attribute " + name1 + " not in kind " + Kind::SPATIAL2D()); } int index2 = listutils::findAttribute(attrList2, name2, type2); if(index2 == 0){ return listutils::typeError("Attribute " + name2 + " not present in second stream"); } if(!listutils::isKind(type2, Kind::SPATIAL2D())){ return listutils::typeError("Attribute " + name2 + " not in kind " + Kind::SPATIAL2D()); } ListExpr attrList = nl->TwoElemList( nl->TwoElemList( nl->SymbolAtom("TID1"), nl->SymbolAtom(TupleIdentifier::BasicType())), nl->TwoElemList( nl->SymbolAtom("TID2"), nl->SymbolAtom(TupleIdentifier::BasicType()))); ListExpr resList = nl->TwoElemList( nl->SymbolAtom(Stream::BasicType()), nl->TwoElemList( nl->SymbolAtom(Tuple::BasicType()), attrList)); return nl->ThreeElemList( nl->SymbolAtom(Symbols::APPEND()), nl->ThreeElemList( nl->IntAtom(-1), // dummy for maxmem nl->IntAtom(index1-1), nl->IntAtom(index2-1)), resList); } /* 1.5 Operator ~realJoinRIndex~ This operator performs a spatial join on two tuple streams. 1.5.1 Type Mapping Signature is: stream(tuple(A)) x stream(tuple(B)) x a[_]i x b[_]j [ x int] -> stream(tuple( A o B)) a[_]i and b[_]j must point to an attribute of type rect in A and B, respectively. The optional integer value is the maximum memory used to cache tuples from the first stream in kB. */ ListExpr realJoinRindexTM(ListExpr args){ string err = "stream(tuple) x stream(tuple) x a_i x b_j [x int] expected"; int len = nl->ListLength(args); if((len!=4) && (len !=5)){ return listutils::typeError(err); } if(!Stream::checkType(nl->First(args)) || !Stream::checkType(nl->Second(args)) || !listutils::isSymbol(nl->Third(args)) || !listutils::isSymbol(nl->Fourth(args))){ return listutils::typeError(err); } if( (len==5) && !CcInt::checkType(nl->Fifth(args))){ return listutils::typeError(err); } ListExpr attrList1 = nl->Second(nl->Second(nl->First(args))); ListExpr attrList2 = nl->Second(nl->Second(nl->Second(args))); string name1 = nl->SymbolValue(nl->Third(args)); string name2 = nl->SymbolValue(nl->Fourth(args)); ListExpr type1; ListExpr type2; int index1 = listutils::findAttribute(attrList1, name1, type1); if(index1 == 0){ return listutils::typeError("Attribute " + name1 + " not present in first stream"); } if(!listutils::isKind(type1, Kind::SPATIAL2D()) && !listutils::isKind(type1, Kind::SPATIAL3D())){ return listutils::typeError("Attribute " + name1 + " not in kind " + Kind::SPATIAL2D() + " and not in kind " + Kind::SPATIAL3D()); } int index2 = listutils::findAttribute(attrList2, name2, type2); if(index2 == 0){ return listutils::typeError("Attribute " + name2 + " not present in second stream"); } if(!listutils::isKind(type2, Kind::SPATIAL2D()) && !listutils::isKind(type2, Kind::SPATIAL3D())){ return listutils::typeError("Attribute " + name2 + " not in kind " + Kind::SPATIAL2D() + " and not in kind " + Kind::SPATIAL3D()); } bool t12d = listutils::isKind(type1, Kind::SPATIAL2D()); bool t22d = listutils::isKind(type2, Kind::SPATIAL2D()); if(t12d != t22d){ return listutils::typeError("Attributes " + name1 + " and " + name2 + " have different dimensions" ); } ListExpr attrList = listutils::concat(attrList1, attrList2); if(!listutils::isAttrList(attrList)){ return listutils::typeError("name conflicts in tuple streams"); } ListExpr resList = nl->TwoElemList( nl->SymbolAtom(Stream::BasicType()), nl->TwoElemList( nl->SymbolAtom(Tuple::BasicType()), attrList)); ListExpr appendList; if(len==5) { appendList = nl->TwoElemList(nl->IntAtom(index1-1), nl->IntAtom(index2-1)); } else { appendList = nl->ThreeElemList( nl->IntAtom(-1), nl->IntAtom(index1-1), nl->IntAtom(index2-1)); } return nl->ThreeElemList( nl->SymbolAtom(Symbols::APPEND()), appendList, resList); } /* 1.4.5 Auxiliary class ~JoinRIndexLocalInfo~ This class gets two tuple streams. From the first one, an RIndex ~ind~ is created. For each tuple of the second stream, we perform a search on ~ind~ to find more result. */ class JoinRindexLocalInfo{ public: /* ~Constructor~ arguments are: ---- _s1 : first stream _s2 : second stream _i1 : index of the rectangle attribute in _s1 _i2 : index of the rectangle attribute in _s2 _tt : list decribung the tuple type of the result mamMem : dummy parameter for compatibility with other classes ---- */ JoinRindexLocalInfo(Word& _s1, Word& _s2, int _i1, int _i2, ListExpr _tt, size_t maxMem): ind(), s2(_s2), i2(_i2) { // build the index from the first stream tt = new TupleType(_tt); Stream s1(_s1); s1.open(); Tuple* t = s1.request(); while(t){ Rectangle<2> r = ((StandardSpatialAttribute<2>*) t->GetAttribute(_i1))->BoundingBox(); ind.insert(r, t->GetTupleId()); t->DeleteIfAllowed(); t = s1.request(); } s1.close(); s2.open(); currentTuple = 0; } /* ~Destructor~ */ ~JoinRindexLocalInfo(){ s2.close(); tt->DeleteIfAllowed(); if(currentTuple){ currentTuple->DeleteIfAllowed(); } } /* ~nextTuple~ Returns the next result tuple or 0 if no more tuples are available. */ Tuple* nextTuple(){ if(lastRes.empty() && (currentTuple!=0)){ // last result is processed currentTuple->DeleteIfAllowed(); currentTuple = 0; } // try to find new results while(lastRes.empty()){ Tuple* t = s2.request(); if(t==0){ return 0; } Rectangle<2> r = ((StandardSpatialAttribute<2>*) t->GetAttribute(i2))->BoundingBox(); ind.findSimple(r, lastRes); if(lastRes.empty()){ t->DeleteIfAllowed(); } else { currentTuple = t; } } pair,TupleId> p1 = lastRes.back(); lastRes.pop_back(); Tuple*result = new Tuple(tt); result->PutAttribute(0, new TupleIdentifier(true, p1.second)); result->PutAttribute(1, new TupleIdentifier(currentTuple->GetTupleId())); return result; } private: RIndex<2,TupleId> ind; // the index used Stream s2; // the second stream int i2; // index of the rectangle attribute in s2 TupleType* tt; // result tuple type vector,TupleId> > lastRes; // result of the last search Tuple* currentTuple; // tuple from s2 used to create lastRes }; /* 1.4.6 Auxiliary class ~SymmJoinRindexLocalInfo~ This class is the symmetric version of JoinRindexLocalInfo. It gets two tuple streams , each having an attribute of type rect. The streams are used alternating. Each tuple is inserted into an Rindex for this stream. Furthermor, a search is performed on the Rindex of the second stream to find results. */ class SymmJoinRindexLocalInfo{ public: /* ~Constructor~ The parameters are: ---- _s1 : first stream _s2 : second stream _i1 : index of the rect attribute in _s1 _i2 : index of the rect attribute in _s2 _tt : list describing the result tuple type maxMem : dummy parameter for compatibility with other classes ---- */ SymmJoinRindexLocalInfo(Word& _s1, Word& _s2, int _i1, int _i2, ListExpr _tt, size_t maxMem): ind1(),ind2(), s1(_s1), s2(_s2), i1(_i1), i2(_i2), tt(0), lastRes(), currentTupleId(0){ tt = new TupleType(_tt); s1.open(); s2.open(); next = false; } /* ~Destructor~ */ ~SymmJoinRindexLocalInfo(){ s1.close(); s2.close(); tt->DeleteIfAllowed(); } /* ~nextTuple~ Returns the next result tuple or 0 if no more tuples are available. */ Tuple* nextTuple(){ while(lastRes.empty()){ next = !next; // switch stream Tuple* t = next?s1.request():s2.request(); if(!t){ // stream exhausted, switch again next = !next; t = next?s1.request():s2.request(); } if(t==0){ // input streams exhausted return 0; } int index = next?i1:i2; Rectangle<2> r = ((StandardSpatialAttribute<2>*) t->GetAttribute(index))->BoundingBox(); currentTupleId = t->GetTupleId(); if(next){ ind1.insert(r, currentTupleId); ind2.findSimple(r, lastRes); } else { ind2.insert(r, currentTupleId); ind1.findSimple(r, lastRes); } t->DeleteIfAllowed(); } pair,TupleId> p1 = lastRes.back(); lastRes.pop_back(); Tuple*result = new Tuple(tt); if(next){ result->PutAttribute(1, new TupleIdentifier(true, p1.second)); result->PutAttribute(0, new TupleIdentifier(currentTupleId)); } else { result->PutAttribute(0, new TupleIdentifier(true, p1.second)); result->PutAttribute(1, new TupleIdentifier(currentTupleId)); } return result; } private: RIndex<2,TupleId> ind1; // index for rectangles of s1 RIndex<2,TupleId> ind2; // index for rectangles of s2 Stream s1; // first tuple stream Stream s2; // second tuple stream int i1; // index of rect attribute in s1 int i2; // index of rect attribute in s2 TupleType* tt; // result tuple type vector,TupleId> > lastRes; // result of the last search TupleId currentTupleId; // tupleId whose corresponding rectangle //has found lastRes bool next; // flag which stream is used, // 1 = first, 0 = second }; /* 1.4.7 Value Mapping */ template int joinRindexVM( Word* args, Word& result, int message, Word& local, Supplier s ){ JLI* li = static_cast(local.addr); switch(message){ case OPEN: { if(li){ delete li; li = 0; local.addr = 0; } CcInt* MaxMem = (CcInt*) args[4].addr; size_t maxMem = (qp->GetMemorySize(s) * 1024); // in kB if(MaxMem->IsDefined() && MaxMem->GetValue()>0){ maxMem = MaxMem->GetValue(); } int i1 = ((CcInt*)(args[5].addr))->GetValue(); int i2 = ((CcInt*)(args[6].addr))->GetValue(); local.addr = new JLI(args[0], args[1],i1,i2, nl->Second(GetTupleResultType(s)), maxMem); return 0; } case REQUEST: { if(!li){ return CANCEL; } result.addr = li->nextTuple(); return result.addr?YIELD:CANCEL; } case CLOSE:{ if(li){ delete li; local.addr = 0; } return 0; } } return -1; } /* 1.4.8 Specification */ const string joinRindexSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" )" "( stream(tuple(A)) x stream(tuple(B)) x a_i x b_j -> " "stream(tuple(( TOD1 : tid)(TID2 : tid))i) " "_ _ joinRIndex[_,_] " "Performes a spatial join on two streams. " "The attributes a_i and b_j must" " be of type rect. The result is a stream of " "tuples with the corresponding Tuple " " ids" " " "query strassen feed extend[B : bbox(.geoData] strassen " "feed extend[B : bbox(.geoData)] joinRindex[B,B] count " " " ") )"; /* 1.4.9 Operator instance */ Operator joinRindex ( "joinRindex", joinRindexSpec, joinRindexVM, Operator::SimpleSelect, joinRindexTM); /* 1.4.10 Specification of ~symmJoinRindex~ */ const string symmJoinRindexSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" )" "( stream(tuple(A)) x stream(tuple(B)) x a_i x b_j -> " "stream(tuple(( TOD1 : tid)(TID2 : tid))i) " "_ _ symmJoinRIndex[_,_] " "Performes a spatial join on two streams. " "The attributes a_i and b_j must" " be of type rect. The result is a stream of " "tuples with the corresponding Tuple " " ids" " " "query strassen feed extend[B : bbox(.geoData] strassen " "feed extend[B : bbox(.geoData)] symmJoinRindex[B,B] count " " " ") )"; /* 1.4.11 Operator instance */ Operator symmJoinRindex ( "symmJoinRindex", symmJoinRindexSpec, joinRindexVM, Operator::SimpleSelect, joinRindexTM); /* 1.4.12 Specification of ~realJoinRindex~ */ const string realJoinRindexSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" )" "( stream(tuple(X)) x stream(tuple(Y)) x a_i x b_j [x int] -> " "stream(tuple(X o Y)) " "_ _ realJoinRindex[a_i, b_j [, maxMem] ] " "Performes a spatial join on two streams. " "The attributes a_i and b_j must" " be of type rect. The result is a stream of " "tuples with intersecting rectangles build as concatenation" " of the source tuples. The optional maxMem argument is the" " maximum size of the tuple cache in kB. Note that there is " " no memory space limitation for the used index." " " "query strassen feed extend[B : bbox(.geoData] {a} strassen " "feed extend[B : bbox(.geoData)] {b} realJoinRindex[B_a,B_b, 1024] count " " " ") )"; ValueMapping realJoinRindexVM[] = { joinRindexVM, StandardSpatialAttribute<2>, StandardSpatialAttribute<2>,2,2,2 > >, joinRindexVM, StandardSpatialAttribute<3>, StandardSpatialAttribute<3>,3,3,3 > >, }; int realJoinIndexSelect(ListExpr args){ ListExpr attrList1 = nl->Second(nl->Second(nl->First(args))); string name1 = nl->SymbolValue(nl->Third(args)); ListExpr type; int index = listutils::findAttribute(attrList1,name1,type); assert(index>0); if(listutils::isKind(type, Kind::SPATIAL2D())){ return 0; } if(listutils::isKind(type, Kind::SPATIAL3D())){ return 1; } return -1; } Operator realJoinRindex ( "realJoinRindex", realJoinRindexSpec, 2, realJoinRindexVM, realJoinIndexSelect, realJoinRindexTM); ValueMapping realJoinRindexVecVM[] = { joinRindexVM, StandardSpatialAttribute<2>, StandardSpatialAttribute<2>,2,2,2 > >, joinRindexVM, StandardSpatialAttribute<3>, StandardSpatialAttribute<3>, 3,3,3 > >, }; Operator realJoinRindexVec ( "realJoinRindexVec", realJoinRindexSpec, 2, realJoinRindexVecVM, realJoinIndexSelect, realJoinRindexTM); /* 2 Algebra Definition 2.1 Algebra Class */ class RIndexAlgebra : public Algebra { public: RIndexAlgebra() : Algebra() { AddOperator(&insertRindex); AddOperator(&findRindex); AddOperator(&statRindex); AddOperator(&joinRindex); joinRindex.SetUsesMemory(); AddOperator(&symmJoinRindex); symmJoinRindex.SetUsesMemory(); AddOperator(&realJoinRindex); realJoinRindex.SetUsesMemory(); AddOperator(&realJoinRindexVec); realJoinRindexVec.SetUsesMemory(); } }; /* 2.2 Algebra Initialization */ extern "C" Algebra* InitializeRIndexAlgebra( NestedList* nlRef, QueryProcessor* qpRef ) { nl = nlRef; qp = qpRef; return (new RIndexAlgebra()); }