Files
secondo/Algebras/RTree/RTreeAlgebra.cpp
2026-01-23 17:03:45 +08:00

6858 lines
210 KiB
C++

/*
----
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 <iostream>
#include <stack>
#include <limits>
#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,
"<relation> creatertree [<attrname>]"
" where <attrname> 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,
"<relation> creatertree [<attrname>]"
" where <attrname> 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,
"<relation> creatertree [<attrname>]"
" where <attrname> 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,
"<relation> creatertree [<attrname>]"
" where <attrname> 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,
"<relation> creatertree [<attrname>]"
" where <attrname> 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<unsigned dim>
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<dim, TupleId>*rtree = static_cast<R_Tree<dim, TupleId>*>(result.addr);
relation = (Relation*)args[0].addr;
attrIndex = ((CcInt*)args[2].addr)->GetIntval() - 1;
iter = relation->MakeScan();
while( (tuple = iter->GetNextTuple()) != 0 )
{
if( ((StandardSpatialAttribute<dim>*)(tuple->
GetAttribute(attrIndex)))->IsDefined() )
{
BBox<dim> box = ((StandardSpatialAttribute<dim>*)(tuple->
GetAttribute(attrIndex)))->BoundingBox();
if (box.IsDefined()) {
R_TreeLeafEntry<dim, TupleId> e( box, tuple->GetTupleId() );
rtree->Insert( e );
}
}
tuple->DeleteIfAllowed();
}
delete iter;
return 0;
}
template<unsigned dim>
int CreateRTreeStreamSpatial(Word* args, Word& result, int message,
Word& local, Supplier s)
{
Word wTuple;
R_Tree<dim, TupleId> *rtree =
(R_Tree<dim, TupleId>*)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<dim>*)tuple->
GetAttribute(attrIndex))->IsDefined() &&
((TupleIdentifier *)tuple->GetAttribute(tidIndex))->
IsDefined() )
{
BBox<dim> box = ((StandardSpatialAttribute<dim>*)tuple->
GetAttribute(attrIndex))->BoundingBox();
if (box.IsDefined()) {
R_TreeLeafEntry<dim, TupleId> 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<unsigned dim>
int CreateRTreeRelRect(Word* args, Word& result, int message,
Word& local, Supplier s)
{
Relation* relation;
int attrIndex;
GenericRelationIterator* iter;
Tuple* tuple;
R_Tree<dim, TupleId> *rtree =
(R_Tree<dim, TupleId>*)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<dim> *box = (BBox<dim>*)tuple->GetAttribute(attrIndex);
if( box->IsDefined() )
{
R_TreeLeafEntry<dim, TupleId> e( *box, tuple->GetTupleId() );
rtree->Insert( e );
}
tuple->DeleteIfAllowed();
}
delete iter;
return 0;
}
template<unsigned dim>
int CreateRTreeStreamRect(Word* args, Word& result, int message,
Word& local, Supplier s)
{
Word wTuple;
R_Tree<dim, TupleId> *rtree =
(R_Tree<dim, TupleId>*)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<dim>*)tuple->
GetAttribute(attrIndex))->IsDefined() &&
((TupleIdentifier *)tuple->GetAttribute(tidIndex))->
IsDefined() )
{
BBox<dim> *box = (BBox<dim>*)tuple->GetAttribute(attrIndex);
if( box->IsDefined() )
{
R_TreeLeafEntry<dim, TupleId> 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<unsigned dim>
int CreateRTree2LSpatial(Word* args, Word& result, int message,
Word& local, Supplier s)
{
Word wTuple;
R_Tree<dim, TwoLayerLeafInfo> *rtree =
(R_Tree<dim, TwoLayerLeafInfo>*)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<dim>*)tuple->
GetAttribute(attrIndex))->IsDefined() &&
((TupleIdentifier *)tuple->GetAttribute(tidIndex))->
IsDefined() &&
((CcInt*)tuple->GetAttribute(tuple->GetNoAttributes()-2))->
IsDefined() &&
((CcInt*)tuple->GetAttribute(tuple->GetNoAttributes()-1))->
IsDefined() )
{
BBox<dim> box = ((StandardSpatialAttribute<dim>*)tuple->
GetAttribute(attrIndex))->BoundingBox();
if (box.IsDefined()) {
R_TreeLeafEntry<dim, TwoLayerLeafInfo> 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<unsigned dim>
int CreateRTree2LRect(Word* args, Word& result, int message,
Word& local, Supplier s)
{
Word wTuple;
R_Tree<dim, TwoLayerLeafInfo> *rtree =
(R_Tree<dim, TwoLayerLeafInfo>*)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<dim>*)tuple->
GetAttribute(attrIndex))->IsDefined() &&
((TupleIdentifier *)tuple->GetAttribute(tidIndex))->
IsDefined() &&
((CcInt*)tuple->GetAttribute(tuple->GetNoAttributes()-2))->
IsDefined() &&
((CcInt*)tuple->GetAttribute(tuple->GetNoAttributes()-1))->
IsDefined() )
{
BBox<dim> *box = (BBox<dim>*)tuple->GetAttribute(attrIndex);
if( box->IsDefined() )
{
R_TreeLeafEntry<dim, TwoLayerLeafInfo>
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\" ) "
"( <text>((rel (tuple (x1 t1)...(xn tn)))) xi)"
" -> (rtree<d> (tuple ((x1 t1)...(xn tn))) ti false)\n"
"((stream (tuple (x1 t1)...(xn tn) (id tid))) xi)"
" -> (rtree<d> (tuple ((x1 t1)...(xn tn))) ti false)\n"
"((stream (tuple (x1 t1)...(xn tn) "
"(id tid)(low int)(high int))) xi)"
" -> (rtree<d> (tuple ((x1 t1)...(xn tn))) ti true)</text--->"
"<text>_ creatertree [ _ ]</text--->"
"<text>Creates an rtree<d>. The key type ti must "
"be of kind SPATIAL2D, SPATIAL3D, SPATIAL4D or Spatial8D, "
"or of type rect, rect2, rect3, rect4 or rect8.</text--->"
"<text>let myrtree = Kreis feed extend[id: tupleid(.)] "
"creatertree[Gebiet]</text--->"
") )";
/*
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<dim>
if(!listutils::isRTreeDescription(rtreeDescription)){
return listutils::typeError("Expects 1st argument to be of type "
"'rtree<dim>(<tuple-type>,bool)'.");
}
// second a relation
if(!listutils::isRelDescription(relDescription)){
return listutils::typeError("Expects 2nd argument to be of type "
"'rel(<tuple-type>)'.");
}
// 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<dim> 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 <unsigned dim>
struct WindowIntersectsLocalInfo
{
Relation* relation;
R_Tree<dim, TupleId>* rtree;
BBox<dim> *searchBox;
bool first;
};
template <unsigned dim>
int WindowIntersects( Word* args, Word& result,
int message, Word& local,
Supplier s )
{
WindowIntersectsLocalInfo<dim> *localInfo;
switch (message)
{
case OPEN :
{
localInfo = new WindowIntersectsLocalInfo<dim>;
localInfo->rtree = (R_Tree<dim, TupleId>*)args[0].addr;
localInfo->relation = (Relation*)args[1].addr;
localInfo->first = true;
localInfo->searchBox =
new BBox<dim> (
(((StandardSpatialAttribute<dim> *)args[2].addr)->
BoundingBox()) );
assert(localInfo->rtree != 0);
assert(localInfo->relation != 0);
local.setAddr(localInfo);
return 0;
}
case REQUEST :
{
localInfo = (WindowIntersectsLocalInfo<dim>*)local.addr;
R_TreeLeafEntry<dim, TupleId> 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<dim>*)local.addr;
delete localInfo->searchBox;
delete localInfo;
local.setAddr(Address(0));
}
return 0;
}
}
return 0;
}
# else
// progress version
template <unsigned dim>
class WindowIntersectsLocalInfo: public ProgressLocalInfo
{
public:
Relation* relation;
R_Tree<dim, TupleId>* rtree;
BBox<dim> *searchBox;
bool first;
int completeCalls;
int completeReturned;
};
template <unsigned dim>
int WindowIntersects( Word* args, Word& result,
int message, Word& local,
Supplier s )
{
WindowIntersectsLocalInfo<dim> *localInfo;
localInfo = (WindowIntersectsLocalInfo<dim>*)local.addr;
switch (message)
{
case OPEN :
{
//local info kept over many calls of OPEN!
//useful for loopjoin
if ( !localInfo ) // first time
{
localInfo = new WindowIntersectsLocalInfo<dim>;
localInfo->completeCalls = 0;
localInfo->completeReturned = 0;
localInfo->sizesInitialized = false;
localInfo->sizesChanged = false;
localInfo->rtree = (R_Tree<dim, TupleId>*)args[0].addr;
localInfo->relation = (Relation*)args[1].addr;
}
localInfo->first = true;
localInfo->searchBox =
new BBox<dim> (
(((StandardSpatialAttribute<dim> *)args[2].addr)->
BoundingBox()) );
assert(localInfo->rtree != 0);
assert(localInfo->relation != 0);
local.setAddr(localInfo);
return 0;
}
case REQUEST :
{
R_TreeLeafEntry<dim, TupleId> 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\" )"
"( <text>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<d> and ti in {rect<d>} U SPATIAL<d>D, for"
" d in {2, 3, 4, 8}</text--->"
"<text>_ _ windowintersects [ _ ]</text--->"
"<text>Uses the given rtree to find all tuples"
" in the given relation with .xi intersects the "
" argument value's bounding box.</text--->"
"<text>query citiesInd cities windowintersects"
" [r] consume; where citiesInd "
"is e.g. created with 'let citiesInd = "
"cities creatertree [pos]'</text--->"
") )";
/*
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<dim>
if(!listutils::isRTreeDescription(rtreeDescription)){
return listutils::typeError("Expects 1st argument to be of type "
"'rtree<dim>(<tuple-type>,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<dim> 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 <unsigned dim, class LeafInfo>
struct WindowIntersectsSLocalInfo
{
R_Tree<dim, LeafInfo>* rtree;
BBox<dim> *searchBox;
TupleType *resultTupleType;
bool first;
};
template <unsigned dim>
int WindowIntersectsSStandard( Word* args, Word& result,
int message, Word& local,
Supplier s )
{
switch (message)
{
case OPEN :
{
WindowIntersectsSLocalInfo<dim, TupleId> *localInfo =
new WindowIntersectsSLocalInfo<dim, TupleId>();
localInfo->rtree = (R_Tree<dim, TupleId>*)args[0].addr;
localInfo->first = true;
localInfo->searchBox =
new BBox<dim> (
(((StandardSpatialAttribute<dim> *)args[1].addr)->
BoundingBox()) );
localInfo->resultTupleType =
new TupleType(nl->Second(GetTupleResultType(s)));
local.setAddr(localInfo);
return 0;
}
case REQUEST :
{
WindowIntersectsSLocalInfo<dim, TupleId> *localInfo =
(WindowIntersectsSLocalInfo<dim, TupleId>*)local.addr;
R_TreeLeafEntry<dim, TupleId> 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<dim, TupleId>* localInfo =
(WindowIntersectsSLocalInfo<dim, TupleId>*)local.addr;
delete localInfo->searchBox;
localInfo->resultTupleType->DeleteIfAllowed();
delete localInfo;
local.setAddr(Address(0));
}
return 0;
}
}
return 0;
}
template <unsigned dim>
int WindowIntersectsSDoubleLayer( Word* args, Word& result,
int message, Word& local,
Supplier s )
{
switch (message)
{
case OPEN :
{
WindowIntersectsSLocalInfo<dim, TwoLayerLeafInfo> *localInfo =
new WindowIntersectsSLocalInfo<dim, TwoLayerLeafInfo>();
localInfo->rtree =
(R_Tree<dim, TwoLayerLeafInfo>*)args[0].addr;
localInfo->first = true;
localInfo->searchBox =
new BBox<dim> (
(((StandardSpatialAttribute<dim> *)args[1].addr)->
BoundingBox()) );
localInfo->resultTupleType =
new TupleType(nl->Second(GetTupleResultType(s)));
local.setAddr(localInfo);
return 0;
}
case REQUEST :
{
WindowIntersectsSLocalInfo<dim, TwoLayerLeafInfo> *localInfo =
(WindowIntersectsSLocalInfo<dim, TwoLayerLeafInfo>*)
local.addr;
R_TreeLeafEntry<dim, TwoLayerLeafInfo> 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<dim, TwoLayerLeafInfo> *localInfo =
(WindowIntersectsSLocalInfo<dim, TwoLayerLeafInfo>*)
local.addr;
delete localInfo->searchBox;
localInfo->resultTupleType->DeleteIfAllowed();
delete localInfo;
local.setAddr(Address(0));
}
return 0;
}
}
return 0;
}
# else
// progress version
template <unsigned dim, class LeafInfo>
struct WindowIntersectsSLocalInfo: public ProgressLocalInfo
{
R_Tree<dim, LeafInfo>* rtree;
BBox<dim> *searchBox;
TupleType *resultTupleType;
bool first;
int completeCalls;
int completeReturned;
};
template <unsigned dim>
int WindowIntersectsSStandard( Word* args, Word& result,
int message, Word& local,
Supplier s )
{
WindowIntersectsSLocalInfo<dim, TupleId> *localInfo;
localInfo = (WindowIntersectsSLocalInfo<dim, TupleId>*)local.addr;
switch (message)
{
case OPEN :
{
//local info kept over many calls of OPEN!
//useful for loopjoin
if ( !localInfo ) // first time
{
localInfo = new WindowIntersectsSLocalInfo<dim, TupleId>;
localInfo->completeCalls = 0;
localInfo->completeReturned = 0;
localInfo->sizesInitialized = false;
localInfo->sizesChanged = false;
localInfo->rtree = (R_Tree<dim, TupleId>*)args[0].addr;
localInfo->resultTupleType =
new TupleType(nl->Second(GetTupleResultType(s)));
}
localInfo->first = true;
localInfo->searchBox =
new BBox<dim> (
(((StandardSpatialAttribute<dim> *)args[1].addr)->
BoundingBox()) );
local.setAddr(localInfo);
return 0;
}
case REQUEST :
{
R_TreeLeafEntry<dim, TupleId> 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 <unsigned dim>
int WindowIntersectsSDoubleLayer( Word* args, Word& result,
int message, Word& local,
Supplier s )
{
WindowIntersectsSLocalInfo<dim, TwoLayerLeafInfo> *localInfo;
localInfo = (WindowIntersectsSLocalInfo<dim, TwoLayerLeafInfo>*)local.addr;
switch (message)
{
case OPEN :
{
//local info kept over many calls of OPEN!
//useful for loopjoin
if ( !localInfo ) // first time
{
localInfo = new WindowIntersectsSLocalInfo<dim, TwoLayerLeafInfo>;
localInfo->completeCalls = 0;
localInfo->completeReturned = 0;
localInfo->sizesInitialized = false;
localInfo->sizesChanged = false;
localInfo->rtree = (R_Tree<dim, TwoLayerLeafInfo>*)args[0].addr;
localInfo->resultTupleType =
new TupleType(nl->Second(GetTupleResultType(s)));
}
localInfo->first = true;
localInfo->searchBox =
new BBox<dim> (
(((StandardSpatialAttribute<dim> *)args[1].addr)->
BoundingBox()) );
local.setAddr(localInfo);
return 0;
}
case REQUEST :
{
WindowIntersectsSLocalInfo<dim, TwoLayerLeafInfo> *localInfo =
(WindowIntersectsSLocalInfo<dim, TwoLayerLeafInfo>*)
local.addr;
R_TreeLeafEntry<dim, TwoLayerLeafInfo> 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\" )"
"( <text>(rtree (tuple((x1 t1)...(xn tn)) ti) x T ->"
" (stream (tuple ((id tid))))"
"For T=rect<d> and ti in {rect<d>} U SPATIAL<d>D, where "
" d in {2, 3, 4, 8}. </text--->"
"<text>_ windowintersectsS [ _ ]</text--->"
"<text>Uses the given rtree to find the tuple "
"identifiers of all entries, whose bounding box intersects "
"with the argument value's bounding box.</text--->"
"<text>query citiesInd windowintersects"
" [r] consume; where citiesInd "
"is e.g. created with 'let citiesInd = "
"cities creatertree [pos]'</text--->"
") )";
/*
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<string> 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 TidIndexPos>
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 TidIndexPos>
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\" )"
"( <text>(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))))"
"</text--->"
"<text>_ _ gettuples</text--->"
"<text>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.</text--->"
"<text>query citiesInd windowintersectsS[r] cities gettuples; "
"where citiesInd is e.g. created with 'letidAttrName2t citiesInd = "
"cities creatertree [pos]'</text--->"
") )";
/*
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<Tuple>::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<string> 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\" )"
"( <text>(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))))"
"</text--->"
"<text>_ _ gettuples2[ attr ] </text--->"
"<text>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.</text--->"
"<text>query citiesInd windowintersectsS[r] cities gettuples2[id]; "
"where citiesInd is e.g. created with 'let citiesInd = "
"cities creatertree [pos]'</text--->"
") )";
/*
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<int, int> > 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\" )"
"( <text>(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))))"
"</text--->"
"<text>_ _ gettuplesdbl[ _ ]</text--->"
"<text>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.</text--->"
"<text>query citiesInd windowintersectsS[r] cities gettuplesdbl; "
"where citiesInd is e.g. created with 'let citiesInd = "
"cities creatertree [pos]'</text--->"
") )";
/*
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<D>~
Signature is
----
creatertree_bulkload<D>: 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<D>~
*/
template<unsigned dim>
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<dim, TupleId> *rtree =
(R_Tree<dim, TupleId>*)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<dim>*)tuple->
GetAttribute(attrIndex))->IsDefined() &&
((TupleIdentifier *)tuple->GetAttribute(tidIndex))->
IsDefined() )
{
BBox<dim> box = ((StandardSpatialAttribute<dim>*)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<dim, TupleId>
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<unsigned dim>
int CreateRTreeBulkLoadStreamL2Spatial(Word* args, Word& result,
int message,
Word& local, Supplier s)
{
int argsOffset = qp->GetNoSons(s)==4?0:1;
Word wTuple;
R_Tree<dim, TwoLayerLeafInfo> *rtree =
(R_Tree<dim, TwoLayerLeafInfo>*)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<dim>*)tuple->
GetAttribute(attrIndex))->IsDefined() &&
((TupleIdentifier *)tuple->GetAttribute(tidIndex))->
IsDefined() &&
((CcInt*)tuple->GetAttribute(tuple->GetNoAttributes()-2))->
IsDefined() &&
((CcInt*)tuple->GetAttribute(tuple->GetNoAttributes()-1))->
IsDefined() )
{
BBox<dim> box = ((StandardSpatialAttribute<dim>*)tuple->
GetAttribute(attrIndex))->BoundingBox();
if (box.IsDefined()) {
R_TreeLeafEntry<dim, TwoLayerLeafInfo> 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<unsigned dim>
int CreateRTreeBulkLoadStreamRect( Word* args, Word& result,
int message,
Word& local, Supplier s )
{
int argOffset = qp->GetNoSons(s)==4?0:1;
Word wTuple;
R_Tree<dim, TupleId> *rtree =
(R_Tree<dim, TupleId>*)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<dim> *box = (BBox<dim>*)tuple->GetAttribute(attrIndex);
if( box->IsDefined() &&
((TupleIdentifier *)tuple->GetAttribute(tidIndex))->IsDefined()
)
{
R_TreeLeafEntry<dim, TupleId>
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<unsigned dim>
int CreateRTreeBulkLoadStreamL2Rect(Word* args, Word& result, int message,
Word& local, Supplier s)
{
int argOffset = qp->GetNoSons(s)==4?0:1;
Word wTuple;
R_Tree<dim, TwoLayerLeafInfo> *rtree =
(R_Tree<dim, TwoLayerLeafInfo>*)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<dim>*)tuple->
GetAttribute(attrIndex))->IsDefined() &&
((TupleIdentifier *)tuple->GetAttribute(tidIndex))->
IsDefined() &&
((CcInt*)tuple->GetAttribute(tuple->GetNoAttributes()-2))->
IsDefined() &&
((CcInt*)tuple->GetAttribute(tuple->GetNoAttributes()-1))->
IsDefined() )
{
BBox<dim> *box = (BBox<dim>*)tuple->GetAttribute(attrIndex);
if( box->IsDefined() )
{
R_TreeLeafEntry<dim, TwoLayerLeafInfo>
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<D>~
*/
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\" ) "
"(<text>(stream (tuple (x1 t1)...(xn tn) (id tid))) xi)"
" -> (rtree<d> (tuple ((x1 t1)...(xn tn))) ti false)\n"
"((stream (tuple (x1 t1)...(xn tn) "
"(id tid)(low int)(high int))) xi)"
" -> (rtree<d> (tuple ((x1 t1)...(xn tn))) ti true)</text--->"
"<text>bulkloadrtree [ _ ]</text--->"
"<text>Creates an rtree<D> 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.</text--->"
"<text>let myrtree = Kreis feed projectextend[ ; TID: tupleid(.), "
"MBR: bbox(.Gebiet)] sortby[MBR asc] bulkloadrtree[MBR]</text--->"
"<text></text--->"
") )";
/*
5.2. Definition of Operator ~creatertree\_bulkload<D>~
*/
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<dim> 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<dim> 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<dim> 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<unsigned dim, class LeafInfo>
int RTreeTreeHeightVM( Word* args, Word& result, int message,
Word& local, Supplier s )
{
R_Tree<dim, LeafInfo> *rtree = (R_Tree<dim, LeafInfo>*) args[0].addr;
result = qp->ResultStorage( s );
CcInt *res = (CcInt*) result.addr;
res->Set( true, rtree->Height() );
return 0;
}
template<unsigned dim, class LeafInfo>
int RTreeNoOfNodesVM( Word* args, Word& result, int message,
Word& local, Supplier s )
{
R_Tree<dim, LeafInfo> *rtree = (R_Tree<dim, LeafInfo>*) args[0].addr;
result = qp->ResultStorage( s );
CcInt *res = (CcInt*) result.addr;
res->Set( true, rtree->NodeCount() );
return 0;
}
template<unsigned dim, class LeafInfo>
int RTreeNoOfEntriesVM( Word* args, Word& result, int message,
Word& local, Supplier s )
{
R_Tree<dim, LeafInfo> *rtree = (R_Tree<dim, LeafInfo>*) args[0].addr;
result = qp->ResultStorage( s );
CcInt *res = (CcInt*) result.addr;
res->Set( true, rtree->EntryCount() );
return 0;
}
template<unsigned dim, class LeafInfo>
int RTreeBboxVM( Word* args, Word& result, int message,
Word& local, Supplier s )
{
R_Tree<dim, LeafInfo> *rtree = (R_Tree<dim, LeafInfo>*) args[0].addr;
result = qp->ResultStorage( s );
Rectangle<dim> *res = (Rectangle<dim> *) result.addr;
*res = rtree->BoundingBox();
return 0;
}
template<unsigned dim, class LeafInfo>
int RTreeGetRootNodeVM( Word* args, Word& result, int message,
Word& local, Supplier s )
{
R_Tree<dim, LeafInfo> *rtree = (R_Tree<dim, LeafInfo>*) 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\" ) "
"(<text>(rtree<D> -> int</text--->"
"<text>treeheight( _ )</text--->"
"<text>Returns the height of the R-tree.</text--->"
"<text>query treeheight(strassen_geoData)</text--->"
"<text>Always defined. Counting starts with level "
"'0' for the root node level.</text--->"
") )";
const string RTreeNoOfEntriesSpec =
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
"\"Example\" \"Comment\" ) "
"(<text>(rtree<D> -> int</text--->"
"<text>no_entries( _ )</text--->"
"<text>Returns the R-tree's number of entries (stored objects).</text--->"
"<text>query no_entries(strassen_geoData)</text--->"
"<text>Always defined.</text--->"
") )";
const string RTreeNoOfNodesSpec =
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
"\"Example\" \"Comment\" ) "
"(<text>(rtree<D> -> int</text--->"
"<text>no_nodes( _ )</text--->"
"<text>Returns the R-tree's number of nodes.</text--->"
"<text>query no_nodes(strassen_geoData)</text--->"
"<text>Always defined.</text--->"
") )";
const string RTreeBboxSpec =
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
"\"Example\" \"Comment\" ) "
"(<text>(rtree<D> -> rect<D></text--->"
"<text>bbox( _ )</text--->"
"<text>Returns the minimum bounding rectangle for "
"the complete R-tree.</text--->"
"<text>query bbox(strassen_geoData)</text--->"
"<text>Rectangle will be undefined for an empty R-tree.</text--->"
") )";
const string RTreeGetRootNodeSpec =
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
"\"Example\" \"Comment\" ) "
"(<text>rtree<D> -> int</text--->"
"<text>getRootNode( _ )</text--->"
"<text>Returns R-tree's record number of root node.</text--->"
"<text>query getRootNode(strassen_geoData)</text--->"
"<text>Always defined.</text--->"
") )";
/*
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<D>)
(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<dim> 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<unsigned dim>
int RTreeNodesVM( Word* args, Word& result, int message,
Word& local, Supplier s )
{
RTreeNodesLocalInfo<dim> *lci;
switch( message )
{
case OPEN:
{
lci = new RTreeNodesLocalInfo<dim>;
local.setAddr(lci);
lci->firstCall = true;
lci->finished = false;
lci->resultTupleType =
new TupleType(nl->Second(GetTupleResultType(s)));
lci->rtree = (R_Tree<dim, TupleId>*) args[0].addr;
return 0;
}
case REQUEST :
{
if(local.addr == NULL)
return CANCEL;
lci = (RTreeNodesLocalInfo<dim> *)local.addr;
if(lci->finished)
return CANCEL;
IntrospectResult<dim> 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<dim>(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<dim> *)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\" ) "
"(<text>(rtree<D> (tuple ((x1 t1)...(xn tn))) ti false) "
"-> stream(tuple((level int) (nodeId int) (MBR rect<D>) \n"
" (fatherId int) (isLeaf bool) \n"
" (minEntries int) (maxEntries int) \n"
" (countEntries int)))</text--->"
"<text>nodes( _ )</text--->"
"<text>Iterates the complete R-tree creating a stream of tuples"
"describing all nodes and leaf entries.</text--->"
"<text></text--->"
"<text></text--->"
") )";
/*
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\" ) "
"(<text>(rtree<D> (tuple ((x1 t1)...(xn tn))) ti false) "
"-> stream(tuple((nodeid int)(bbox key)(tid tupleid))</text--->"
"<text>entries( _ )</text--->"
"<text>Returns a stream of tuples which are all the nodes contain bbox in"
"a leaf entry.</text--->"
"<text></text--->"
"<text></text--->"
") )";
template<unsigned dim,class LeafInfo>
int RTreeEntriesVM( Word* args, Word& result, int message,
Word& local, Supplier s )
{
RTreeNodesLocalInfo<dim> *lci;
IntrospectResult<dim> node;
switch( message )
{
case OPEN:
{
lci = new RTreeNodesLocalInfo<dim>;
local.setAddr(lci);
lci->firstCall = true;
lci->finished = false;
lci->resultTupleType =
new TupleType(nl->Second(GetTupleResultType(s)));
lci->rtree = (R_Tree<dim, TupleId>*) 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<dim> box;
if(local.addr == NULL)
return CANCEL;
lci = (RTreeNodesLocalInfo<dim> *)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<dim>(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<dim>(box));
tuple->PutAttribute(2, new CcInt(true, tupleid));
result.setAddr(tuple);
return YIELD;
}
}
case CLOSE :
{
if(local.addr)
{
lci = (RTreeNodesLocalInfo<dim> *)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<dim> 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<unsigned dim,class LeafInfo>
int getFileInfoRtreeValueMap(Word* args, Word& result, int message,
Word& local, Supplier s)
{
result = qp->ResultStorage(s);
FText* restext = (FText*)(result.addr);
R_Tree<dim, LeafInfo> *rtree = (R_Tree<dim, LeafInfo> *)(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\" ) "
"( <text>(btree(tuple(x) ti) xi -> text)</text--->"
"<text>getFileInfo( _ )</text--->"
"<text>Retrieve statistical infomation on the file(s) used by the rtree "
"instance.</text--->"
"<text>query getFileInfo(Trains_Trip_rtree)</text--->"
") )";
/*
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\" ) "
"(<text>(stream (tuple (x1 t1)...(xn tn) (id tid))) xi)"
" -> (rtree<d> (tuple ((x1 t1)...(xn tn))) ti false)\n"
"((stream (tuple (x1 t1)...(xn tn) "
"(id tid)(low int)(high int))) xi)"
" -> (rtree<d> (tuple ((x1 t1)...(xn tn))) ti true)</text--->"
"<text>_ _ updatebulkloadrtree [ _ ]</text--->"
"<text>Creates an rtree<D> 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.</text--->"
"<text>let UTOrdered_2 = UTOrdered_1 UTOrdered feed addid sortby[UTrip asc] "
"filter[tid2int(.TID) > 30000] updatebulkloadrtree[UTrip]</text--->"
"<text></text--->"
") )";
/*
UpdateBulkLoad for r-tree
*/
ListExpr UpdateBulkLoadTypeMap(ListExpr args)
{
// cout<<"UpdateBulkLoadTypeMap"<<endl;
// check number of parameters
if( nl->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<unsigned dim>
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<R_Tree<3,TupleId>*>(args[0].addr);
//R_Tree<3,TupleId>* rtree_temp = (R_Tree<3,TupleId>*)qp->ResultStorage(s).addr;
R_Tree<dim,TupleId>* rtree_in1 =
static_cast<R_Tree<dim,TupleId>*>(args[0].addr);
R_Tree<dim,TupleId>* rtree_temp =
(R_Tree<dim,TupleId>*)qp->ResultStorage(s).addr;
rtree_temp->CloseFile();
// R_Tree<dim, TupleId> *rtree =
// new R_Tree<3,TupleId>(rtree_in1->FileId(),4000);
R_Tree<dim, TupleId> *rtree =
new R_Tree<dim,TupleId>(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<dim>*)tuple->
GetAttribute(attrIndex))->IsDefined() &&
((TupleIdentifier *)tuple->GetAttribute(tidIndex))->
IsDefined() )
{
BBox<dim> box = ((StandardSpatialAttribute<dim>*)tuple->
GetAttribute(attrIndex))->BoundingBox();
if (box.IsDefined()) {
R_TreeLeafEntry<dim, TupleId> 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<D>~
*/
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<D>) x int --> stream(tuple((NodeId int) (MBR rect<D>)
(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 <InfoType iTyp>
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<dim> 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<unsigned dim, class LeafInfo>
struct GetSonsInfo{
int index;
int maxEntries;
R_TreeNode<dim, LeafInfo>* father;
TupleType* ttype;
long nodeId;
bool IsRoot;
GetSonsInfo( int i, int m, R_TreeNode<dim, LeafInfo>* 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 <unsigned dim, class LeafInfo>
bool checkRecordId(R_Tree<dim, LeafInfo>* rtree, int nodeId)
{
bool findRID = false;
if ( (nodeId > 0)
&& (nodeId != static_cast<int>(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<rhs.xVal;
}
};
/*
insertion or deletion event at x-value for MBR with named index
eventComp is the comparator for the sorted set
*/
seg_node* buildTree(set<double> &yVals)
{
seg_node* sTree;
set<double>::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<subsetSize; i++)
yValiter++;
set<double> yValsRight (yValiter++, yVals.end());
set<double> 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<double> &yVals, set<double> &zVals)
{
quad_node* qTree;
set<double>::iterator yValiter = yVals.begin();
set<double>::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<subsetSizeZ; i++)
zValiter++;
set<double> zValsTop (zValiter++, zVals.end());
set<double> 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<subsetSizeY; i++)
yValiter++;
set<double> yValsRight (yValiter++, yVals.end());
set<double> 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<subsetSizeY; i++)
yValiter++;
set<double> yValsRight (yValiter++, yVals.end());
set<double> 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<subsetSizeZ; i++)
zValiter++;
set<double> zValsTop (zValiter++, zVals.end());
set<double> 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<unsigned dim>
double getSweepAreas2D(vector< Rectangle<dim> > 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<BBox.size())
{
if ((abs((BBox[it].MinD(0)-BBox[it].MaxD(0))/BBox[it].MaxD(0))<1E-8)
||(abs((BBox[it].MinD(1)-BBox[it].MaxD(1))/BBox[it].MaxD(1))<1E-8))
{ BBox.erase(BBox.begin()+it); }
else
{ it++;
}
}
if (BBox.empty()) return 0.0; //area of empty rectangle is 0
seg_node* segmentTree;
set<double> xVals;
set<double> yVals;
multiset<event, eventComp> insertMBR;
multiset<event, eventComp> deleteMBR;
multiset<event, eventComp>::iterator iterateInsert;
multiset<event, eventComp>::iterator iterateDelete;
for (unsigned int i=0; i<BBox.size(); i++)
//build sorted lists of values and events
{
xVals.insert(BBox[i].MinD(0));
xVals.insert(BBox[i].MaxD(0));
insertMBR.insert(event(BBox[i].MinD(0),i));
deleteMBR.insert(event(BBox[i].MaxD(0),i));
yVals.insert(BBox[i].MinD(1));
yVals.insert(BBox[i].MaxD(1));
}
segmentTree = buildTree(yVals);
//initialization of the x-value-list
double cover = 0.0;
double x = 0.0;
set<double>::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<unsigned dim>
double getSweepAreas(vector< Rectangle<dim> > 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<BBox.size())
{
zero = false;
for (unsigned int j=0; j<dim; j++)
zero |= (abs((BBox[it].MinD(j)-BBox[it].MaxD(j))/BBox[it].MaxD(j))<1E-8);
if (zero)
{ BBox.erase(BBox.begin()+it); }
else
{ it++; }
}
if (BBox.empty()) return 0.0; //area of empty rectangle is 0
quad_node* quadTreeYZ;
set<double> xVals[dim-1];
set<double> yVals;
set<double> zVals;
multiset<event, eventComp> insertMBR[dim-1];
multiset<event, eventComp> deleteMBR[dim-1];
multiset<event, eventComp>::iterator iterateInsert[dim-1];
multiset<event, eventComp>::iterator iterateDelete[dim-1];
for (unsigned int i=0; i<BBox.size(); i++)
//build sorted lists of values and events
{
for (unsigned int j=0; j<dim-2; j++)
{
xVals[j].insert(BBox[i].MinD(j));
xVals[j].insert(BBox[i].MaxD(j));
insertMBR[j].insert(event(BBox[i].MinD(j),i));
deleteMBR[j].insert(event(BBox[i].MaxD(j),i));
}
yVals.insert(BBox[i].MinD(dim-2));
yVals.insert(BBox[i].MaxD(dim-2));
zVals.insert(BBox[i].MinD(dim-1));
zVals.insert(BBox[i].MaxD(dim-1));
}
quadTreeYZ = buildTree(yVals, zVals);
set<double>::iterator xValiter[dim-1];
double coversweep[dim];
for (unsigned int j=0; j<dim; j++)
{
coversweep[j] = 0.0;
}
double x[dim-1];
set<int> xindex[dim-1];
unsigned int di;
bool again;
set<int>::iterator indexIter;
//initialization of the lists
for (unsigned int j=0; j<dim-3; j++)
{
xValiter[j] = xVals[j].begin();
iterateInsert[j] = insertMBR[j].begin();
iterateDelete[j] = deleteMBR[j].begin();
x[j] = *xValiter[j];
xValiter[j]++;
while ((iterateInsert[j]!=insertMBR[j].end())&&
((*iterateInsert[j]).xVal == x[j])) {
//insert index of valid rectangles at position <x>
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 <x>
int index = (*iterateDelete[dim-3]).index;
xindex[dim-3].erase(index);
iterateDelete[dim-3]++;
bool all = true;
for (unsigned int j=0; j<dim-3;j++)
all &=(xindex[j].find(index)!=xindex[j].end());
if (all)
deleteNode(quadTreeYZ,
BBox[index].MinD(dim-2),
BBox[index].MaxD(dim-2),
BBox[index].MinD(dim-1),
BBox[index].MaxD(dim-1));
}
while ((iterateInsert[dim-3]!=insertMBR[dim-3].end())&&
((*iterateInsert[dim-3]).xVal == x[dim-3])) {
//insert rectangles from tree at position <x>
int index = (*iterateInsert[dim-3]).index;
xindex[dim-3].insert(index);
iterateInsert[dim-3]++;
bool all = true;
for (unsigned int j=0; j<dim-3;j++)
all &=(xindex[j].find(index)!=xindex[j].end());
if (all)
insertNode(quadTreeYZ,
BBox[index].MinD(dim-2),
BBox[index].MaxD(dim-2),
BBox[index].MinD(dim-1),
BBox[index].MaxD(dim-1));
}
coversweep[dim-2] = (quadTreeYZ->measure);
di = dim-3;
again = true;
while (again)
{
//set "sweepline" to next position <x>
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<dim-3;j++)
all &=(xindex[j].find(index)!=xindex[j].end());
if (all)
deleteNode(quadTreeYZ,
BBox[index].MinD(dim-2),
BBox[index].MaxD(dim-2),
BBox[index].MinD(dim-1),
BBox[index].MaxD(dim-1));
}
}
xValiter[di] = xVals[di].begin();
iterateInsert[di] = insertMBR[di].begin();
iterateDelete[di] = deleteMBR[di].begin();
x[di] = *xValiter[di];
xValiter[di]++;
again = true;
}
while ((di!=dim-3)&&
(iterateDelete[di]!=deleteMBR[di].end())&&
((*iterateDelete[di]).xVal == x[di])) {
//delete index of non-valid rectangles at position <x>
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 <x>
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<unsigned dim>
int RTreeGetNodeInfoVM( Word* args, Word& result, int message,
Word& local, Supplier s )
{
GetSonsInfo<dim, TupleId>* gsi;
switch( message )
{
case OPEN:
{
int nodeId = ((CcInt*)args[1].addr)->GetIntval();
R_Tree<dim, TupleId>* tree = (R_Tree<dim, TupleId>*) 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<dim, TupleId>* f = new R_TreeNode<dim, TupleId>
(false, 0, maxEntr);
tree->GetNode(nodeId, *f);
int m = f->EntryCount();
bool isRootNode = (nodeId==static_cast<int>(tree->RootRecordId()));
gsi = new GetSonsInfo<dim, TupleId>(-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<dim, TupleId>*)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<dim> > sonBB; //vector of BoundingBoxes of sons
for (int i=0; i<gsi->maxEntries; 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; i<gsi->maxEntries-1; i++)
{
for (int j= i+1; j<gsi->maxEntries; 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<dim>(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<dim, TupleId>*)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\" ) "
"(<text>(rtree<D> (tuple ((x1 t1)...(xn tn))) ti false) x int"
"-> stream(tuple((NodeId int) (MBR rect<D>) (NoOfSons int) \n"
" (IsLeafNode bool) (IsRootNode bool) \n"
" (MBRsize real) (MBRdead real) (MBRoverlapSize real) \n"
" (MBRoverlapsNo int) (MBRdensity real)))</text--->"
"<text>getNodeInfo( _ , _ )</text--->"
"<text>This operator allows introspection of an RTree. It creates a "
"stream of a tuple, which describes one node of the R-Tree.</text--->"
"<text>query getNodeInfo(strassen_geoData_rtree, 2);</text--->"
"<text>Stream is empty, if given record no is not existing.</text--->"
") )";
/*
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<NODEINFO> // 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<D>) x int --> stream(tuple((NodeId int) (SonId int)
(SonMBR rect<D>)))
----
*/
/*
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<unsigned dim>
int RTreeGetNodeSonsVM( Word* args, Word& result, int message,
Word& local, Supplier s )
{
GetSonsInfo<dim, TupleId>* gsi;
switch( message )
{
case OPEN:
{
int nodeId = ((CcInt*)args[1].addr)->GetIntval();
R_Tree<dim, TupleId>* tree = (R_Tree<dim, TupleId>*) 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<dim, TupleId>* f = new R_TreeNode<dim, TupleId>
(false, 0, maxEntr);
tree->GetNode(nodeId, *f);
int m = f->EntryCount();
bool isRootNode = (nodeId==static_cast<int>(tree->RootRecordId()));
gsi = new GetSonsInfo<dim, TupleId>(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<dim, TupleId>*)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<dim>(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<dim>* son = gsi->father->
GetInternalEntry(gsi->index);
tuple->PutAttribute(1, new CcInt(true, son->pointer));
tuple->PutAttribute(2, new Rectangle<dim>(son->box));
result.setAddr(tuple);
gsi->index++;
return YIELD;
}
case CLOSE :
{
if(local.addr)
{
gsi = (GetSonsInfo<dim, TupleId>*)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\" ) "
"(<text>(rtree<D> (tuple ((x1 t1)...(xn tn))) ti false) x int "
"-> stream(tuple((NodeId int) (SonId int) (SonMBR rect<D>)))</text--->"
"<text>getNodeSons( _ , _ )</text--->"
"<text>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.</text--->"
"<text>query getNodeSons(strassen_geodata_rtree, 2);</text--->"
"<text>Stream is empty, if given record no is not existing.</text--->"
") )";
/*
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<NODESONS> // 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<D>) x int --> stream(tuple((NodeId int) (TupleID tid)))
(EntryMBR rect<D>)))
----
*/
/*
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<unsigned dim>
int RTreeGetLeafEntriesVM( Word* args, Word& result, int message,
Word& local, Supplier s )
{
GetSonsInfo<dim, TupleId>* gsi;
switch( message )
{
case OPEN:
{
int nodeId = ((CcInt*)args[1].addr)->GetIntval();
R_Tree<dim, TupleId>* tree = (R_Tree<dim, TupleId>*) 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<dim, TupleId>* f = new R_TreeNode<dim, TupleId>
(false, 0, maxEntr);
tree->GetNode(nodeId, *f);
int m = f->EntryCount();
bool isRootNode = (nodeId==static_cast<int>(tree->RootRecordId()));
gsi = new GetSonsInfo<dim, TupleId>(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<dim, TupleId>*)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<dim,TupleId>* entry = gsi->father->
GetLeafEntry(gsi->index);
tuple->PutAttribute(1, new TupleIdentifier(true, entry->info));
tuple->PutAttribute(2, new Rectangle<dim>(entry->box));
result.setAddr(tuple);
gsi->index++;
return YIELD;
}
case CLOSE :
{
if(local.addr)
{
gsi = (GetSonsInfo<dim, TupleId>*)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\" ) "
"(<text>(rtree<D> (tuple ((x1 t1)...(xn tn))) ti false) x int "
"-> stream(tuple((NodeId int)(TupleID tid)(EntryMBR rect<D>)))</text--->"
"<text>getLeafEntries( _ , _ )</text--->"
"<text>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.</text--->"
"<text>query getLeafEntries(strassen_geodata_rtree, 2);</text--->"
"<text>Stream is empty, if given record no is not existing.</text--->"
") )";
/*
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<LEAFENTRIES> // 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<Tuple>::BasicType()),
nl->TwoElemList( nl->SymbolAtom(Tuple::BasicType()),
attrList));
}
/*
LocalInfo class for directSpatialJoin
*/
template<int dim>
class DspatialJoinLocal{
public:
DspatialJoinLocal(R_Tree<dim, TupleId>* _r1,
GenericRelation* _rel1,
R_Tree<dim, TupleId>* _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<dim, TupleId> n1 = r1->Root();
R_TreeNode<dim, TupleId> 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<dim>) +
s_q_ll * sizeof(pair<TupleId,TupleId>);
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<TupleId, Tuple*>(noTuples1);
lru2 = new LRU<TupleId, Tuple*>(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<TupleId,Tuple*>(3);
lru2 = new LRU<TupleId, Tuple*>(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<TupleId,Tuple*>* victim = lru1->deleteLast();
victim->value->DeleteIfAllowed();
delete victim;
}
while(!lru2->empty()){
LRUEntry<TupleId,Tuple*>* 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<dim,TupleId>* r1;
R_Tree<dim,TupleId>* r2;
GenericRelation* rel1;
GenericRelation* rel2;
TupleType* tt;
std::stack< pair<R_TreeInternalEntry<dim>,
R_TreeInternalEntry<dim> > > q_ii;
std::stack< pair<R_TreeInternalEntry<dim>,
R_TreeLeafEntry<dim, TupleId> > > q_il;
std::stack< pair<R_TreeLeafEntry<dim, TupleId>,
R_TreeInternalEntry<dim> > > q_li;
std::queue< pair<TupleId, TupleId > > q_ll;
int max1;
int max2;
LRU<TupleId, Tuple*>* lru1;
LRU<TupleId, Tuple*>* lru2;
bool allempty() const{
return q_ll.empty() && q_li.empty() && q_il.empty() && q_ii.empty();
}
void processNodes(const R_TreeNode<dim, TupleId> & n1,
const R_TreeNode<dim, TupleId> & 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<TupleId, TupleId> 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<TupleId,Tuple*>* 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<TupleId,Tuple*>* victim = lru2->use(id,t1);
if(victim){
victim->value->DeleteIfAllowed();
delete victim;
}
return t1;
}
/*
Processes two leaf nodes
*/
void processLeafLeaf( const R_TreeNode<dim, TupleId> & n1,
const R_TreeNode<dim, TupleId> & n2){
for(int i1=0; i1 < n1.EntryCount(); i1++){
R_TreeLeafEntry<dim,TupleId>* e1 = n1.GetLeafEntry(i1);
for(int i2=0;i2 < n2.EntryCount(); i2++){
R_TreeLeafEntry<dim,TupleId>* e2 = n2.GetLeafEntry(i2);
if(e1->box.Intersects(e2->box)){
pair<TupleId,TupleId> p(e1->info, e2->info);
q_ll.push(p);
}
}
}
}
void processLeafInner( const R_TreeNode<dim, TupleId> & n1,
const R_TreeNode<dim, TupleId> & n2){
for(int i1=0; i1 < n1.EntryCount(); i1++){
R_TreeLeafEntry<dim,TupleId> e1 = *n1.GetLeafEntry(i1);
for(int i2=0;i2 < n2.EntryCount(); i2++){
R_TreeInternalEntry<dim> e2 = *n2.GetInternalEntry(i2);
if(e1.box.Intersects(e2.box)){
pair< R_TreeLeafEntry<dim,TupleId>,
R_TreeInternalEntry<dim> > p(e1,e2);
q_li.push(p);
}
}
}
}
void processInnerLeaf( const R_TreeNode<dim, TupleId> & n1,
const R_TreeNode<dim, TupleId> & n2){
for(int i1=0; i1 < n1.EntryCount(); i1++){
R_TreeInternalEntry<dim> e1 = *n1.GetInternalEntry(i1);
for(int i2=0;i2 < n2.EntryCount(); i2++){
R_TreeLeafEntry<dim, TupleId> e2 = *n2.GetLeafEntry(i2);
if(e1.box.Intersects(e2.box)){
pair<R_TreeInternalEntry<dim>,
R_TreeLeafEntry<dim, TupleId> > p(e1,e2);
q_il.push(p);
}
}
}
}
void processInnerInner( const R_TreeNode<dim, TupleId> & n1,
const R_TreeNode<dim, TupleId> & n2){
for(int i1=0; i1 < n1.EntryCount(); i1++){
R_TreeInternalEntry<dim> e1 = *n1.GetInternalEntry(i1);
for(int i2=0;i2 < n2.EntryCount(); i2++){
R_TreeInternalEntry<dim> e2 = *n2.GetInternalEntry(i2);
if(e1.box.Intersects(e2.box)){
pair<R_TreeInternalEntry<dim>,
R_TreeInternalEntry<dim> > p(e1,e2);
q_ii.push(p);
}
}
}
}
bool processIL(){
if(q_il.empty()){
return false;
}
pair<R_TreeInternalEntry<dim>,
R_TreeLeafEntry<dim, TupleId> > p = q_il.top();
q_il.pop();
R_TreeNode<dim,TupleId> n1(true,1,max1);
r1->GetNode(p.first.pointer,n1);
if(n1.IsLeaf()){
for(int i1=0;i1<n1.EntryCount();i1++){
R_TreeLeafEntry<dim,TupleId> e1 = *n1.GetLeafEntry(i1);
if(p.second.box.Intersects(e1.box)){
pair<TupleId,TupleId> pn(e1.info, p.second.info);
q_ll.push(pn);
}
}
} else {
for(int i1=0;i1<n1.EntryCount();i1++){
R_TreeInternalEntry<dim> e1 = *n1.GetInternalEntry(i1);
if(p.second.box.Intersects(e1.box)){
pair<R_TreeInternalEntry<dim>,
R_TreeLeafEntry<dim,TupleId> > pn(e1, p.second);
q_il.push(pn);
}
}
}
return true;
}
bool processLI(){
if(q_li.empty()){
return false;
}
pair<R_TreeLeafEntry<dim, TupleId>,
R_TreeInternalEntry<dim> > p = q_li.top();
q_li.pop();
R_TreeNode<dim,TupleId> n2(true,1,max2);
r2->GetNode(p.second.pointer,n2);
if(n2.IsLeaf()){
for(int i2=0;i2<n2.EntryCount();i2++){
R_TreeLeafEntry<dim,TupleId> e2 = *n2.GetLeafEntry(i2);
if(p.first.box.Intersects(e2.box)){
pair<TupleId,TupleId> pn(p.first.info, e2.info);
q_ll.push(pn);
}
}
} else {
for(int i2=0;i2<n2.EntryCount();i2++){
R_TreeInternalEntry<dim> e2 = *n2.GetInternalEntry(i2);
if(p.first.box.Intersects(e2.box)){
pair<R_TreeLeafEntry<dim, TupleId>,
R_TreeInternalEntry<dim> > pn(p.first, e2);
q_li.push(pn);
}
}
}
return true;
}
bool processII(){
if(q_ii.empty()){
return false;
}
pair<R_TreeInternalEntry<dim>, R_TreeInternalEntry<dim> > p = q_ii.top();
q_ii.pop();
R_TreeNode<dim,TupleId> n1(true,1,max1);
R_TreeNode<dim,TupleId> n2(true,1,max2);
r1->GetNode(p.first.pointer, n1);
r2->GetNode(p.second.pointer, n2);
processNodes(n1,n2);
return true;
}
};
template<int dim>
int dspatialJoinVM1(Word* args, Word& result, int message,
Word& local, Supplier s){
DspatialJoinLocal<dim>* li = (DspatialJoinLocal<dim>*) local.addr;
switch(message){
case OPEN: {
if(li){
delete li;
}
ListExpr ttl = nl->Second(GetTupleResultType(s));
R_Tree<dim,TupleId>* r1 =
(R_Tree<dim,TupleId>*) args[0].addr;
GenericRelation* rel1 = (GenericRelation*) args[1].addr;
R_Tree<dim,TupleId>* r2 =
(R_Tree<dim,TupleId>*) args[2].addr;
GenericRelation* rel2 = (GenericRelation*) args[3].addr;
int maxMem = qp->GetMemorySize(s) * 1024 * 1024;
local.addr = new DspatialJoinLocal<dim>(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\" ) "
"(<text> rtree x rtree -> stream(tuple([TID1 : tid, TID2 : tid]))"
"</text--->"
"<text> _ _ dspatialJoin </text--->"
"<text>This operator returns such pairs of tuple id's "
"having overlapping bounding boxes within the rtrees"
".</text--->"
"<text>query strassen_geoData_rtree "
"strassen_geoData_rtree dspatialJoin count</text--->"
"<text></text--->"
") )";
/*
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);
}