4300 lines
123 KiB
C++
4300 lines
123 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 Module Ordered Relation Algebra
|
|
|
|
Winter 2009 Nicolai Voget
|
|
|
|
[TOC]
|
|
|
|
1 Overview
|
|
|
|
The Ordered Relational Algebra implements the type constructor ~orel~.
|
|
|
|
For more information about what the functions should do, see the
|
|
OrderedRelation.h header file.
|
|
|
|
2 Defines, includes, and constants
|
|
|
|
*/
|
|
#include "OrderedRelationAlgebra.h"
|
|
#include "StandardTypes.h"
|
|
#include "ListUtils.h"
|
|
#include "Progress.h"
|
|
#include "Algebras/Relation-C++/RelationAlgebra.h"
|
|
#include "Tools/Flob/DbArray.h"
|
|
#include <limits>
|
|
#include "Symbols.h"
|
|
#include "Algebras/Standard-C++/LongInt.h"
|
|
#include "Stream.h"
|
|
#include "AlgebraTypes.h"
|
|
|
|
//#define DEBUG_OREL
|
|
|
|
#ifdef DEBUG_OREL
|
|
#define DEBUG_OREL2
|
|
#endif
|
|
|
|
using namespace std;
|
|
|
|
/*
|
|
2.1 Structs and Tools
|
|
|
|
2.1.1 Priority Queue and Visited Sections for Shortest Path Computations
|
|
|
|
*/
|
|
struct NodeEntry
|
|
{
|
|
NodeEntry(){}
|
|
|
|
NodeEntry(const int id, const int index, const int before)
|
|
: nodeId(id), arrayIndex(index), beforeNodeId(before)
|
|
{}
|
|
|
|
NodeEntry(const NodeEntry& nE)
|
|
: nodeId(nE.nodeId), arrayIndex(nE.arrayIndex),
|
|
beforeNodeId(nE.beforeNodeId)
|
|
{}
|
|
|
|
~NodeEntry()
|
|
{}
|
|
|
|
inline int Compare(const NodeEntry nE) const
|
|
{
|
|
return Compare(nE.GetNodeId());
|
|
}
|
|
|
|
inline int Compare(const int nId) const
|
|
{
|
|
if (nodeId < nId) return -1;
|
|
if (nodeId > nId) return 1;
|
|
return 0;
|
|
}
|
|
|
|
inline void operator=( const NodeEntry nE)
|
|
{
|
|
nodeId = nE.nodeId;
|
|
arrayIndex = nE.arrayIndex;
|
|
beforeNodeId = nE.beforeNodeId;
|
|
}
|
|
|
|
ostream& Print(ostream& os) const
|
|
{
|
|
os << "Node Number: " << nodeId;
|
|
os << ", Predecessor Node Number: " << beforeNodeId;
|
|
os << ", array Index: " << arrayIndex;
|
|
os << endl;
|
|
return os;
|
|
}
|
|
|
|
inline int GetNodeId() const
|
|
{
|
|
return nodeId;
|
|
}
|
|
|
|
inline int GetArrayIndex() const
|
|
{
|
|
return arrayIndex;
|
|
}
|
|
|
|
inline int GetBeforeNodeId() const
|
|
{
|
|
return beforeNodeId;
|
|
}
|
|
|
|
inline void SetNodeId(const int id)
|
|
{
|
|
nodeId = id;
|
|
}
|
|
|
|
inline void SetArrayIndex(const int index)
|
|
{
|
|
arrayIndex = index;
|
|
}
|
|
|
|
inline void SetBeforeNodeId (const int id)
|
|
{
|
|
beforeNodeId = id;
|
|
}
|
|
|
|
int nodeId;
|
|
int arrayIndex;
|
|
int beforeNodeId;
|
|
};
|
|
|
|
struct TreeEntry
|
|
{
|
|
|
|
TreeEntry(){};
|
|
|
|
TreeEntry(const NodeEntry elem, int l = -1, int r = -1)
|
|
: nEntry(elem), left(l), right(r)
|
|
{}
|
|
|
|
TreeEntry(const TreeEntry& te)
|
|
: nEntry(te.GetNodeEntry()), left (te.GetLeft()), right(te.GetRight())
|
|
{}
|
|
|
|
~TreeEntry()
|
|
{}
|
|
|
|
inline NodeEntry GetNodeEntry() const
|
|
{
|
|
return nEntry;
|
|
}
|
|
|
|
inline int GetLeft() const
|
|
{
|
|
return left;
|
|
}
|
|
|
|
inline int GetRight() const
|
|
{
|
|
return right;
|
|
}
|
|
|
|
inline void operator=(const TreeEntry nTEntry)
|
|
{
|
|
nEntry = nTEntry.GetNodeEntry();
|
|
left = nTEntry.GetLeft();
|
|
right = nTEntry.GetRight();
|
|
}
|
|
|
|
inline void SetNodeEntry(const NodeEntry& ne)
|
|
{
|
|
nEntry = ne;
|
|
}
|
|
|
|
inline void SetLeft(const int n)
|
|
{
|
|
left = n;
|
|
}
|
|
|
|
inline void SetRight(const int n)
|
|
{
|
|
right = n;
|
|
}
|
|
|
|
inline int Compare(const TreeEntry& nE) const
|
|
{
|
|
return GetNodeEntry().Compare(nE.GetNodeEntry());
|
|
}
|
|
|
|
inline int Compare(const int nodeId) const
|
|
{
|
|
return GetNodeEntry().Compare(nodeId);
|
|
}
|
|
|
|
ostream& Print(ostream& os) const
|
|
{
|
|
os << "Entry: ";
|
|
nEntry.Print(os);
|
|
os << "left: " << left << ", right: " << right << endl;
|
|
return os;
|
|
}
|
|
|
|
NodeEntry nEntry;
|
|
int left,right;
|
|
};
|
|
|
|
struct NodeEntryTree
|
|
{
|
|
NodeEntryTree()
|
|
: tree(0)
|
|
{
|
|
fFree = 0;
|
|
}
|
|
|
|
NodeEntryTree(const int n)
|
|
: tree(n)
|
|
{
|
|
fFree = 0;
|
|
}
|
|
|
|
~NodeEntryTree()
|
|
{}
|
|
|
|
inline void Destroy()
|
|
{
|
|
tree.Destroy();
|
|
}
|
|
|
|
inline void Remove()
|
|
{
|
|
tree.Destroy();
|
|
delete this;
|
|
};
|
|
|
|
int Find(const TreeEntry& te) const
|
|
{
|
|
int i = 0;
|
|
if (tree.Size() < 1) return -1;
|
|
while (i < fFree)
|
|
{
|
|
TreeEntry test = GetTreeEntry(i);
|
|
switch(test.Compare(te))
|
|
{
|
|
case 0:
|
|
{
|
|
return i;
|
|
break;
|
|
}
|
|
case -1:
|
|
{
|
|
if (test.GetRight() != -1) i = test.GetRight();
|
|
else return i;
|
|
break;
|
|
}
|
|
case 1:
|
|
{
|
|
if (test.GetLeft() != -1) i = test.GetLeft();
|
|
else return i;
|
|
break;
|
|
}
|
|
default: // should never been reached
|
|
{
|
|
return -1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return -1; // should never been reached
|
|
};
|
|
|
|
int Find(const int nId) const
|
|
{
|
|
int i = 0;
|
|
if (tree.Size() < 1) return -1;
|
|
while (i < fFree)
|
|
{
|
|
TreeEntry test = GetTreeEntry(i);
|
|
switch(test.GetNodeEntry().Compare(nId))
|
|
{
|
|
case 0:
|
|
{
|
|
return i;
|
|
break;
|
|
}
|
|
case 1:
|
|
{
|
|
if (test.GetLeft() != -1) i = test.GetLeft();
|
|
else return i;
|
|
break;
|
|
}
|
|
case -1:
|
|
{
|
|
if (test.GetRight() != -1) i = test.GetRight();
|
|
else return i;
|
|
break;
|
|
}
|
|
default: // should never been reached
|
|
{
|
|
return -1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return -1; // should never been reached
|
|
};
|
|
|
|
void Insert(const TreeEntry nE, int& newPos)
|
|
{
|
|
|
|
newPos = Find(nE);
|
|
if (newPos < 0 )
|
|
{
|
|
newPos = fFree;
|
|
fFree++;
|
|
tree.Put(newPos, nE);
|
|
}
|
|
else
|
|
{
|
|
if (newPos < fFree)
|
|
{
|
|
TreeEntry test = GetTreeEntry(newPos);
|
|
switch(test.Compare(nE))
|
|
{
|
|
case 1:
|
|
{
|
|
test.SetLeft(fFree);
|
|
tree.Put(newPos,test);
|
|
tree.Put(fFree,nE);
|
|
fFree++;
|
|
break;
|
|
}
|
|
case -1:
|
|
{
|
|
test.SetRight(fFree);
|
|
tree.Put(newPos,test);
|
|
tree.Put(fFree,nE);
|
|
fFree++;
|
|
break;
|
|
}
|
|
case 0:
|
|
{
|
|
tree.Put(newPos,nE);
|
|
break;
|
|
}
|
|
default: //should never been reached
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
void SetIndex (const int pos, const int index)
|
|
{
|
|
assert (pos > -1 && pos < fFree);
|
|
TreeEntry te = GetTreeEntry(pos);
|
|
NodeEntry nE = te.GetNodeEntry();
|
|
nE.SetArrayIndex(index);
|
|
te.SetNodeEntry(nE);
|
|
tree.Put(pos,te);
|
|
}
|
|
|
|
inline int GetIndex (const int pos) const
|
|
{
|
|
assert(pos > -1 && pos < fFree);
|
|
return GetTreeEntry(pos).GetNodeEntry().GetArrayIndex();
|
|
}
|
|
|
|
void SetBeforeNodeId(const int pos, const int before)
|
|
{
|
|
assert(pos > -1 && pos < fFree);
|
|
TreeEntry te = GetTreeEntry(pos);
|
|
NodeEntry ne = te.GetNodeEntry();
|
|
ne.SetBeforeNodeId(before);
|
|
te.SetNodeEntry(ne);
|
|
tree.Put(pos,te);
|
|
}
|
|
|
|
TreeEntry GetTreeEntry(const int pos) const
|
|
{
|
|
assert(pos > -1 && pos < fFree);
|
|
TreeEntry te;
|
|
tree.Get(pos,te);
|
|
return te;
|
|
}
|
|
|
|
bool IsNode(const int pos, const int nodeNumber) const
|
|
{
|
|
assert(pos > -1 && pos < fFree);
|
|
|
|
if (GetTreeEntry(pos).GetNodeEntry().GetNodeId() == nodeNumber)
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
ostream& Print(ostream& os) const
|
|
{
|
|
os << "Start NodeEntryTree: " << endl;
|
|
TreeEntry tE;
|
|
if (fFree > 0)
|
|
{
|
|
for (int i = 0; i < tree.Size(); i++)
|
|
{
|
|
tree.Get(i,tE);
|
|
tE.Print(os);
|
|
}
|
|
}
|
|
os << "Ende NodeEntryTree" << endl;
|
|
return os;
|
|
}
|
|
|
|
DbArray<TreeEntry> tree;
|
|
int fFree;
|
|
};
|
|
|
|
|
|
struct PQEntryOrel
|
|
{
|
|
PQEntryOrel() {}
|
|
|
|
PQEntryOrel(const int node, const int before, const double dist,
|
|
const double prio)
|
|
: nodeNumber(node), beforeNodeNumber(before), distFromStart(dist),
|
|
prioval(prio)
|
|
{}
|
|
|
|
PQEntryOrel(const PQEntryOrel& nE)
|
|
: nodeNumber(nE.nodeNumber), beforeNodeNumber(nE.beforeNodeNumber),
|
|
distFromStart(nE.distFromStart), prioval(nE.prioval)
|
|
{}
|
|
|
|
~PQEntryOrel()
|
|
{}
|
|
|
|
ostream& Print(ostream& os) const
|
|
{
|
|
os << "Node Number: " << nodeNumber;
|
|
os << ", Predecessor Node Number: " << beforeNodeNumber;
|
|
os << ", Prioval: " << prioval;
|
|
os << ", Distance From Start: " << distFromStart;
|
|
os << endl;
|
|
return os;
|
|
}
|
|
|
|
int nodeNumber;
|
|
int beforeNodeNumber;
|
|
double distFromStart;
|
|
double prioval;
|
|
|
|
};
|
|
|
|
struct PQueueOrel
|
|
{
|
|
|
|
PQueueOrel()
|
|
: prioQ(0)
|
|
{
|
|
firstFree = 0;
|
|
}
|
|
|
|
PQueueOrel(const int n)
|
|
: prioQ(n)
|
|
{
|
|
firstFree = 0;
|
|
}
|
|
|
|
~PQueueOrel()
|
|
{}
|
|
|
|
inline void Destroy()
|
|
{
|
|
prioQ.Destroy();
|
|
}
|
|
|
|
inline void Clear()
|
|
{
|
|
prioQ.clean();
|
|
firstFree = 0;
|
|
}
|
|
|
|
inline bool IsEmpty() const
|
|
{
|
|
if (firstFree == 0 ) return true;
|
|
else return false;
|
|
}
|
|
|
|
ostream& Print(ostream& os) const
|
|
{
|
|
os << "Start PriorityQueue: " << endl;
|
|
PQEntryOrel pE;
|
|
if (firstFree > 0)
|
|
{
|
|
for (int i = 0; i < firstFree; i++)
|
|
{
|
|
prioQ.Get(i,pE);
|
|
pE.Print(os);
|
|
}
|
|
}
|
|
os << "Ende PriorityQueue" << endl;
|
|
return os;
|
|
}
|
|
|
|
/*
|
|
If a node is reached second time and the prioval of the second way is
|
|
smaller than on the path found before. The prioval, the valFromStart and the
|
|
position in the priority queue must be corrected.
|
|
|
|
*/
|
|
|
|
void CorrectPosition ( const int actPosIndex, const PQEntryOrel& nEle,
|
|
NodeEntryTree* pNodeTree )
|
|
{
|
|
int testIndex = actPosIndex;
|
|
int n = actPosIndex;
|
|
PQEntryOrel test;
|
|
test.prioval = -1;
|
|
bool found = false;
|
|
while ( testIndex > 0 && !found )
|
|
{
|
|
|
|
if ( ( testIndex % 2 ) == 0 ) n = ( testIndex-2 ) / 2;
|
|
else n = ( testIndex -1 ) / 2;
|
|
if ( n >= 0 )
|
|
{
|
|
prioQ.Get ( n, test );
|
|
if ( test.prioval > nEle.prioval ||
|
|
(test.prioval == nEle.prioval &&
|
|
test.distFromStart > nEle.distFromStart))
|
|
{
|
|
Swap ( n, nEle, testIndex, test, pNodeTree );
|
|
}
|
|
else
|
|
{
|
|
found = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
found = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Append ( const PQEntryOrel nE, int pNElemPos,
|
|
NodeEntryTree *pNodeTree)
|
|
{
|
|
int actPos = firstFree;
|
|
prioQ.Put(actPos, nE );
|
|
pNodeTree->Insert(TreeEntry(NodeEntry(nE.nodeNumber,
|
|
actPos,
|
|
nE.beforeNodeNumber),
|
|
-1,-1),
|
|
pNElemPos);
|
|
CorrectPosition(actPos, nE, pNodeTree );
|
|
firstFree++;
|
|
}
|
|
|
|
void Insert ( const PQEntryOrel nE, NodeEntryTree *pNodeTree,
|
|
DbArray<PQEntryOrel>* spTree)
|
|
{
|
|
int pNElemPos = pNodeTree->Find(nE.nodeNumber);
|
|
spTree->Append(nE);
|
|
if (pNElemPos < 0)
|
|
Append(nE, pNElemPos, pNodeTree);
|
|
else
|
|
{
|
|
if ( pNElemPos > -1 && pNElemPos < pNodeTree->fFree)
|
|
{
|
|
if (!pNodeTree->IsNode(pNElemPos, nE.nodeNumber))
|
|
{
|
|
Append(nE, pNElemPos, pNodeTree);
|
|
}
|
|
else
|
|
{
|
|
int index = pNodeTree->GetIndex(pNElemPos);
|
|
if (index > -1 && index < firstFree)
|
|
{
|
|
PQEntryOrel test;
|
|
prioQ.Get(index, test);
|
|
if (test.prioval > nE.prioval)
|
|
{
|
|
prioQ.Put(index, nE);
|
|
pNodeTree->SetBeforeNodeId(pNElemPos, nE.beforeNodeNumber);
|
|
CorrectPosition(index, nE, pNodeTree);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Swap(const int testIndex, const PQEntryOrel& last,
|
|
int& actIndex, const PQEntryOrel& test1,
|
|
NodeEntryTree* pNodeTree)
|
|
{
|
|
prioQ.Put(testIndex, last);
|
|
pNodeTree->SetIndex(pNodeTree->Find(last.nodeNumber),testIndex);
|
|
prioQ.Put(actIndex, test1);
|
|
pNodeTree->SetIndex(pNodeTree->Find(test1.nodeNumber),actIndex);
|
|
actIndex = testIndex;
|
|
}
|
|
|
|
PQEntryOrel* GetAndDeleteMin(NodeEntryTree* pNodeTree)
|
|
{
|
|
if (firstFree <= 0) return 0;
|
|
PQEntryOrel result, last, test1, test2;
|
|
prioQ.Get(0,result);
|
|
PQEntryOrel* retValue = new PQEntryOrel(result);
|
|
int tRet = pNodeTree->Find(result.nodeNumber);
|
|
prioQ.Get(firstFree-1,last);
|
|
prioQ.Put(0,last);
|
|
prioQ.Put(firstFree-1, PQEntryOrel(-1,
|
|
-1,
|
|
numeric_limits<double>::max(),
|
|
numeric_limits<double>::max()));
|
|
firstFree--;
|
|
int pNewPos = pNodeTree->Find(last.nodeNumber);
|
|
pNodeTree->SetIndex(pNewPos,0);
|
|
pNodeTree->SetIndex(tRet,-1);
|
|
int actIndex = 0;
|
|
int testIndex = 0;
|
|
bool found = false;
|
|
while (testIndex < firstFree && !found)
|
|
{
|
|
testIndex = 2*actIndex + 1;
|
|
if (testIndex < firstFree-1)
|
|
{
|
|
prioQ.Get(testIndex, test1);
|
|
prioQ.Get(testIndex+1, test2);
|
|
if (test1.prioval < last.prioval ||
|
|
test2.prioval < last.prioval)
|
|
{
|
|
if (test1.prioval <= test2.prioval)
|
|
Swap(testIndex, last, actIndex, test1, pNodeTree);
|
|
else
|
|
Swap(testIndex+1, last, actIndex, test2, pNodeTree);
|
|
}
|
|
else
|
|
{
|
|
if(test1.prioval == last.prioval &&
|
|
test1.distFromStart < last.distFromStart)
|
|
Swap(testIndex, last, actIndex, test1, pNodeTree);
|
|
else
|
|
{
|
|
if (test2.prioval == last.prioval &&
|
|
test2.distFromStart < last.distFromStart)
|
|
Swap(testIndex+1, last, actIndex, test2, pNodeTree);
|
|
else
|
|
found = true;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (testIndex > 0 && testIndex == firstFree-1)
|
|
{
|
|
prioQ.Get(testIndex,test1);
|
|
if (test1.prioval < last.prioval ||
|
|
(test1.prioval == last.prioval &&
|
|
test1.distFromStart < last.distFromStart))
|
|
Swap(testIndex, last, actIndex, test1, pNodeTree);
|
|
else
|
|
found = true;
|
|
}
|
|
else
|
|
{
|
|
found = true;
|
|
}
|
|
}
|
|
}
|
|
return retValue;
|
|
}
|
|
|
|
DbArray<PQEntryOrel> prioQ;
|
|
int firstFree;
|
|
};
|
|
|
|
struct OShortestPathInfo
|
|
{
|
|
OShortestPathInfo()
|
|
{
|
|
resTuples = 0;
|
|
iter = 0;
|
|
counter = 0;
|
|
seqNoAttrIndex = 0;
|
|
resultSelect = 0;
|
|
}
|
|
|
|
~OShortestPathInfo(){};
|
|
|
|
TupleBuffer* resTuples;
|
|
GenericRelationIterator* iter;
|
|
int counter;
|
|
int seqNoAttrIndex;
|
|
int resultSelect;
|
|
};
|
|
|
|
|
|
/*
|
|
3 Implementation
|
|
3.1 OrderedRelationIterator
|
|
|
|
*/
|
|
OrderedRelationIterator::OrderedRelationIterator(const OrderedRelation* orel,
|
|
TupleType* newType /*=0*/,
|
|
const CompositeKey& from,
|
|
const CompositeKey& to):
|
|
tupleType(orel->tupleType), outtype(newType),
|
|
lobFileId(orel->lobFileId),
|
|
appendix(-1) {
|
|
#ifdef DEBUG_OREL
|
|
cout << "Konstruktor_OrelIter" << endl;
|
|
#endif
|
|
tupleType->IncReference();
|
|
fileId = orel->GetFileId();
|
|
if(outtype!=0) outtype->IncReference();
|
|
endOfScan = true;
|
|
if(from.IsDefined() || to.IsDefined()) {
|
|
if(from.IsDefined()) {
|
|
if(to.IsDefined()) {
|
|
it = orel->tupleFile->SelectRangePrefetched(from.GetSmiKey(),
|
|
to.GetSmiKey());
|
|
} else {
|
|
it = orel->tupleFile->SelectRightRangePrefetched(from.GetSmiKey());
|
|
}
|
|
} else {
|
|
it = orel->tupleFile->SelectLeftRangePrefetched(to.GetSmiKey());
|
|
}
|
|
} else {
|
|
it = orel->tupleFile->SelectAllPrefetched();
|
|
}
|
|
if (it!=0) {
|
|
endOfScan = false;
|
|
}
|
|
}
|
|
|
|
OrderedRelationIterator::~OrderedRelationIterator() {
|
|
tupleType->DeleteIfAllowed();
|
|
if(outtype!=0) outtype->DeleteIfAllowed();
|
|
if(it!=0) delete it;
|
|
return;
|
|
}
|
|
|
|
Tuple* OrderedRelationIterator::GetNextTuple() {
|
|
#ifdef DEBUG_OREL
|
|
cout << "GetNextTuple_OrelIter" << endl;
|
|
#endif
|
|
if(!Advance()) {
|
|
return 0;
|
|
}
|
|
Tuple* t = new Tuple(tupleType);
|
|
if(t->OpenOrel(fileId, lobFileId, it, appendix)) {
|
|
return t;
|
|
} else {
|
|
delete t;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
Tuple* OrderedRelationIterator::GetNextTuple(const list<int>& attrList) {
|
|
if(!Advance()) {
|
|
return 0;
|
|
}
|
|
Tuple* t = new Tuple(tupleType);
|
|
if(t->OpenPartialOrel(fileId,outtype, attrList, lobFileId, it, appendix)) {
|
|
return t;
|
|
} else {
|
|
delete t;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
TupleId OrderedRelationIterator::GetTupleId() const {
|
|
#ifdef DEBUG_OREL
|
|
cout << "GetTupleId_OrelIter" << endl;
|
|
#endif
|
|
return appendix;
|
|
}
|
|
|
|
const CompositeKey& OrderedRelationIterator::GetKey() const {
|
|
#ifdef DEBUG_OREL
|
|
cout << "GetKey" << endl;
|
|
#endif
|
|
return key;
|
|
}
|
|
|
|
bool OrderedRelationIterator::Advance() {
|
|
if(endOfScan) return false;
|
|
if(!it->Next()) {
|
|
key = CompositeKey();
|
|
endOfScan = true;
|
|
return false;
|
|
}
|
|
SmiKey k;
|
|
it->CurrentKey(k);
|
|
key = CompositeKey(k);
|
|
|
|
appendix = key.GetAppendix();
|
|
return (appendix>=MIN_TUPLE_ID);
|
|
}
|
|
|
|
/*
|
|
3.2 OrderedRelation
|
|
|
|
*/
|
|
OrderedRelation::OrderedRelation(ListExpr typeInfo, bool createFiles/*=true*/):
|
|
tupleType(new TupleType(nl->Second(typeInfo))),
|
|
attrExtSize(tupleType->GetNoAttributes()),
|
|
attrSize(tupleType->GetNoAttributes()) {
|
|
#ifdef DEBUG_OREL
|
|
cout << "Konstruktor_Orel(typeInfo)" << endl;
|
|
#endif
|
|
GetKeyStructure(typeInfo, keyElement, keyElemType);
|
|
if(createFiles) {
|
|
tupleFile = new SmiBtreeFile(SmiKey::Composite);
|
|
tupleFile->Create();
|
|
tupleFileId = tupleFile->GetFileId();
|
|
hasLobs = false;
|
|
lobFileId = 0;
|
|
if (tupleType->NumOfFlobs() > 0) {
|
|
hasLobs = true;
|
|
SmiRecordFile rf(false, 0, false);
|
|
if(!rf.Create()) {
|
|
assert(false);
|
|
}
|
|
lobFileId = rf.GetFileId();
|
|
rf.Close();
|
|
}
|
|
}
|
|
noTuples = 0;
|
|
maxId = MIN_TUPLE_ID;
|
|
}
|
|
|
|
OrderedRelation::~OrderedRelation() {
|
|
#ifdef DEBUG_OREL
|
|
cout << "Destruktor_Orel" << endl;
|
|
#endif
|
|
tupleType->DeleteIfAllowed();
|
|
if(tupleFile!=0) {
|
|
tupleFile->Close();
|
|
delete tupleFile;
|
|
}
|
|
}
|
|
|
|
ListExpr OrderedRelation::Out(const ListExpr typeInfo, Word value) {
|
|
#ifdef DEBUG_OREL
|
|
cout << "Out_Orel" << endl;
|
|
#endif
|
|
OrderedRelation* orel = static_cast<OrderedRelation*>(value.addr);
|
|
#ifdef DEBUG_OREL2
|
|
cout << orel->noTuples << endl;
|
|
#endif
|
|
ListExpr result = nl->TheEmptyList();
|
|
ListExpr last = result, tupleList = result;
|
|
|
|
GenericRelationIterator* rit = orel->MakeScan();
|
|
Tuple* t = 0;
|
|
ListExpr tupleTypeInfo = nl->TwoElemList(
|
|
nl->Second(typeInfo),
|
|
nl->IntAtom(nl->ListLength(nl->Second(nl->Second(typeInfo)))));
|
|
|
|
#ifdef DEBUG_OREL2
|
|
cout << "Out:\tvor Iteration" << endl;
|
|
cout << nl->ToString(tupleTypeInfo) << endl;
|
|
int count = 0;
|
|
#endif
|
|
while ((t = rit->GetNextTuple()) !=0) {
|
|
tupleList = t->Out(tupleTypeInfo);
|
|
t->DeleteIfAllowed();
|
|
#ifdef DEBUG_OREL2
|
|
cout << "Tuple No. " << count++ << endl;
|
|
cout << nl->ToString(tupleList) << endl;
|
|
#endif
|
|
if (result == nl->TheEmptyList()) {
|
|
result = nl->Cons(tupleList, nl->TheEmptyList());
|
|
last = result;
|
|
} else {
|
|
last = nl->Append(last,tupleList);
|
|
}
|
|
}
|
|
delete rit;
|
|
return result;
|
|
}
|
|
|
|
Word OrderedRelation::In(const ListExpr typeInfo, const ListExpr value,
|
|
const int errorPos, ListExpr& errorInfo, bool& correct) {
|
|
#ifdef DEBUG_OREL
|
|
cout << "In_Orel" << endl;
|
|
#endif
|
|
#ifdef DEBUG_OREL2
|
|
cout << nl->ToString(typeInfo) << endl;
|
|
#endif
|
|
OrderedRelation* orel = new OrderedRelation(typeInfo);
|
|
int tupleno = 0;
|
|
Tuple* t;
|
|
ListExpr list = value;
|
|
ListExpr first;
|
|
correct=true;
|
|
|
|
ListExpr tupleTypeInfo = nl->TwoElemList(nl->Second(typeInfo),
|
|
nl->IntAtom(nl->ListLength(nl->Second(nl->Second(typeInfo)))));
|
|
|
|
while(!nl->IsEmpty(list)) {
|
|
first = nl->First(list);
|
|
list = nl->Rest(list);
|
|
tupleno++;
|
|
t = Tuple::In(tupleTypeInfo, first, tupleno, errorInfo, correct);
|
|
if(correct) {
|
|
orel->AppendTuple(t);
|
|
t->DeleteIfAllowed();
|
|
} else {
|
|
delete orel;
|
|
return SetWord(Address(0));
|
|
}
|
|
}
|
|
return SetWord(orel);
|
|
}
|
|
|
|
Word OrderedRelation::Create(const ListExpr typeInfo) {
|
|
#ifdef DEBUG_OREL
|
|
cout << "Create_Orel" << endl;
|
|
cout << nl->ToString(typeInfo) << endl;
|
|
#endif
|
|
return SetWord(new OrderedRelation(typeInfo));
|
|
}
|
|
|
|
void OrderedRelation::Delete(const ListExpr typeInfo, Word& value) {
|
|
#ifdef DEBUG_OREL
|
|
cout << "Delete_Orel" << endl;
|
|
#endif
|
|
OrderedRelation* orel = static_cast<OrderedRelation*>(value.addr);
|
|
orel->tupleFile->Close();
|
|
orel->tupleFile->Drop();
|
|
delete orel->tupleFile;
|
|
orel->tupleFile = 0; //to prevent ~OrderedRelation from closing tupleFile
|
|
if (orel->hasLobs) {
|
|
char mode = 0; // orels are never temporarly
|
|
Flob::dropFile(orel->lobFileId, mode);
|
|
SmiRecordFile rf(false, 0, false);
|
|
rf.Open(orel->lobFileId);
|
|
rf.Close();
|
|
rf.Drop();
|
|
}
|
|
delete orel;
|
|
value.addr = 0;
|
|
}
|
|
|
|
bool OrderedRelation::Open(SmiRecord& valueRecord, size_t& offset,
|
|
const ListExpr typeInfo, Word& value) {
|
|
#ifdef DEBUG_OREL
|
|
cout << "Open_Orel" << endl;
|
|
#endif
|
|
//STUB
|
|
OrderedRelation* orel = new OrderedRelation(typeInfo, false);
|
|
|
|
valueRecord.SetPos(offset);
|
|
|
|
valueRecord.Read(orel->noTuples);
|
|
valueRecord.Read(orel->maxId);
|
|
|
|
valueRecord.Read(orel->tupleFileId);
|
|
valueRecord.Read(orel->lobFileId);
|
|
|
|
valueRecord.Read(orel->totalExtSize);
|
|
valueRecord.Read(orel->totalSize);
|
|
|
|
for(int i=0;i<orel->tupleType->GetNoAttributes();i++) {
|
|
valueRecord.Read(orel->attrExtSize[i]);
|
|
}
|
|
for(int i=0;i<orel->tupleType->GetNoAttributes();i++) {
|
|
valueRecord.Read(orel->attrSize[i]);
|
|
}
|
|
|
|
orel->tupleFile = new SmiBtreeFile(SmiKey::Composite);
|
|
orel->tupleFile->Open(orel->tupleFileId);
|
|
|
|
orel->hasLobs = (orel->lobFileId!=0);
|
|
|
|
offset = valueRecord.GetPos();
|
|
value = SetWord(orel);
|
|
return true;
|
|
}
|
|
|
|
|
|
bool OrderedRelation::Save(SmiRecord& valueRecord, size_t& offset,
|
|
const ListExpr typeInfo, Word& value) {
|
|
#ifdef DEBUG_OREL
|
|
cout << "Save_Orel" << endl;
|
|
#endif
|
|
OrderedRelation* orel = static_cast<OrderedRelation*>(value.addr);
|
|
|
|
valueRecord.SetPos(offset);
|
|
valueRecord.Write(orel->noTuples);
|
|
valueRecord.Write(orel->maxId);
|
|
|
|
valueRecord.Write(orel->tupleFileId);
|
|
valueRecord.Write(orel->lobFileId);
|
|
|
|
valueRecord.Write(orel->totalExtSize);
|
|
valueRecord.Write(orel->totalSize);
|
|
|
|
for(int i=0;i<orel->tupleType->GetNoAttributes();i++) {
|
|
valueRecord.Write(orel->attrExtSize[i]);
|
|
}
|
|
for(int i=0;i<orel->tupleType->GetNoAttributes();i++) {
|
|
valueRecord.Write(orel->attrSize[i]);
|
|
}
|
|
|
|
offset = valueRecord.GetPos();
|
|
return true;
|
|
}
|
|
|
|
|
|
void OrderedRelation::Close(const ListExpr typeInfo, Word& value) {
|
|
#ifdef DEBUG_OREL
|
|
cout << "Close_Orel" << endl;
|
|
#endif
|
|
delete (static_cast<OrderedRelation*>(value.addr));
|
|
}
|
|
|
|
|
|
Word OrderedRelation::Clone(const ListExpr typeInfo, const Word& value) {
|
|
#ifdef DEBUG_OREL
|
|
cout << "Clone_Orel" << endl;
|
|
#endif
|
|
OrderedRelation* clone = new OrderedRelation(typeInfo);
|
|
OrderedRelation* orel = static_cast<OrderedRelation*>(value.addr);
|
|
Tuple* t;
|
|
OrderedRelationIterator* iter = (OrderedRelationIterator*)orel->MakeScan();
|
|
while((t = iter->GetNextTuple()) != 0) {
|
|
#ifdef DEBUG_OREL2
|
|
cout << "GotNextTuple" << endl;
|
|
#endif
|
|
clone->AppendTuple(t);
|
|
t->DeleteIfAllowed();
|
|
}
|
|
delete iter;
|
|
return SetWord(clone);
|
|
}
|
|
|
|
|
|
void* OrderedRelation::Cast(void* addr) {
|
|
#ifdef DEBUG_OREL
|
|
cout << "Cast_Orel" << endl;
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
|
|
bool OrderedRelation::CheckKind(const ListExpr typeInfo,
|
|
ListExpr& errorInfo) {
|
|
#ifdef DEBUG_OREL
|
|
cout << "CheckKind_Orel" << endl;
|
|
#endif
|
|
#ifdef DEBUG_OREL2
|
|
cout << nl->ToString(typeInfo) << endl;
|
|
cout << nl->SymbolValue(nl->First(typeInfo)) << endl;
|
|
#endif
|
|
if ( listutils::isOrelDescription(typeInfo) ) {
|
|
return true;
|
|
}
|
|
else {
|
|
errorInfo = nl->Append(errorInfo,
|
|
nl->ThreeElemList(nl->IntAtom(80),
|
|
nl->SymbolAtom(OREL),
|
|
typeInfo));
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
int OrderedRelation::GetNoTuples() const {
|
|
#ifdef DEBUG_OREL
|
|
cout << "GetNoTuples_Orel" << endl;
|
|
#endif
|
|
return noTuples;
|
|
}
|
|
|
|
|
|
double OrderedRelation::GetTotalRootSize() const {
|
|
#ifdef DEBUG_OREL
|
|
cout << "GetTotalRootSize_Orel" << endl;
|
|
#endif
|
|
return noTuples*tupleType->GetCoreSize();
|
|
}
|
|
|
|
|
|
double OrderedRelation::GetTotalRootSize(int i) const {
|
|
#ifdef DEBUG_OREL
|
|
cout << "GetTotalRootSize[i]_Orel" << endl;
|
|
#endif
|
|
return noTuples*tupleType->GetAttributeType(i).coreSize;
|
|
}
|
|
|
|
|
|
double OrderedRelation::GetTotalExtSize() const {
|
|
#ifdef DEBUG_OREL
|
|
cout << "GetTotalExtSize_Orel" << endl;
|
|
#endif
|
|
return totalExtSize;
|
|
}
|
|
|
|
|
|
double OrderedRelation::GetTotalExtSize(int i) const {
|
|
#ifdef DEBUG_OREL
|
|
cout << "GetTotalExtSize[i]_Orel" << endl;
|
|
#endif
|
|
return attrExtSize[i];
|
|
}
|
|
|
|
|
|
double OrderedRelation::GetTotalSize() const {
|
|
#ifdef DEBUG_OREL
|
|
cout << "GetTotalSize_Orel" << endl;
|
|
#endif
|
|
return totalSize;
|
|
}
|
|
|
|
|
|
double OrderedRelation::GetTotalSize(int i) const {
|
|
#ifdef DEBUG_OREL
|
|
cout << "GetTotalSize[i]_Orel" << endl;
|
|
#endif
|
|
return attrSize[i];
|
|
}
|
|
|
|
|
|
void OrderedRelation::Clear() {
|
|
#ifdef DEBUG_OREL
|
|
cout << "Clear_Orel" << endl;
|
|
#endif
|
|
noTuples=0;
|
|
maxId = MIN_TUPLE_ID;
|
|
tupleFile->Truncate();
|
|
if(hasLobs) {
|
|
SmiRecordFile rf(false, 0, false);
|
|
rf.Open(lobFileId);
|
|
rf.Truncate();
|
|
rf.Close();
|
|
}
|
|
for(int i = 0;i<tupleType->GetNoAttributes();i++) {
|
|
attrSize[i] = 0.0;
|
|
attrExtSize[i] = 0.0;
|
|
}
|
|
totalExtSize = 0.0;
|
|
totalSize = 0.0;
|
|
}
|
|
|
|
|
|
void OrderedRelation::AppendTuple(Tuple* t) {
|
|
#ifdef DEBUG_OREL
|
|
cout << "AppendTuple_Orel" << endl;
|
|
#endif
|
|
// ignore tuple if one of the KeyElements is undefined
|
|
for(size_t i=0;i<keyElement.size();i++){
|
|
if(!(t->GetAttribute(keyElement[i])->IsDefined())){
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
SmiRecord record;
|
|
TupleId extension = maxId++;
|
|
bool rc = tupleFile->InsertRecord(GetKey(t, true, extension).GetSmiKey(),
|
|
record);
|
|
assert(rc==true);
|
|
t->SaveOrel(&record, lobFileId, totalExtSize, totalSize, attrExtSize,
|
|
attrSize, false, extension);
|
|
record.Finish();
|
|
noTuples++;
|
|
}
|
|
|
|
|
|
Tuple* OrderedRelation::GetTuple(const TupleId& id,
|
|
const bool dontReportError) const {
|
|
#ifdef DEBUG_OREL
|
|
cout << "GetTuple_Orel" << endl;
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
|
|
Tuple* OrderedRelation::GetTuple(const TupleId& id, const int attrIndex,
|
|
const vector<pair<int, int> >& intervals,
|
|
const bool dontReportError) const {
|
|
return GetTuple(id, dontReportError);
|
|
}
|
|
|
|
|
|
Tuple* OrderedRelation::GetTuple(const CompositeKey& key) const {
|
|
Tuple* t = 0;
|
|
SmiRecord record;
|
|
if(tupleFile->SelectRecord(key.GetSmiKey(), record)) {
|
|
t = new Tuple(tupleType);
|
|
t->OpenOrel(tupleFile->GetFileId(), lobFileId, record,
|
|
key.GetAppendix());
|
|
}
|
|
return t;
|
|
}
|
|
|
|
|
|
Tuple* OrderedRelation::GetTuple(const CompositeKey& key, const int attrIndex,
|
|
const vector<pair<int, int> >& intervals) const {
|
|
Tuple* t = 0;
|
|
if((t=GetTuple(key))!=0)
|
|
t->GetAttribute(attrIndex)->Restrict(intervals);
|
|
return t;
|
|
}
|
|
|
|
bool OrderedRelation::DeleteTuple(Tuple* tuple) {
|
|
return DeleteTuple(tuple, true);
|
|
}
|
|
|
|
bool OrderedRelation::DeleteTuple(Tuple* tuple, bool deleteComplete) {
|
|
CompositeKey key = GetKey(tuple, true, tuple->GetTupleId());
|
|
SmiKeyedFileIterator iter;
|
|
bool ok = false;
|
|
SmiRecord record;
|
|
if(tupleFile->SelectRecord(key.GetSmiKey(), iter, SmiFile::Update))
|
|
ok = iter.Next(record) && iter.DeleteCurrent();
|
|
if(ok) {
|
|
Attribute* nextAttr;
|
|
Flob* nextFlob;
|
|
|
|
noTuples--;
|
|
totalExtSize -= tuple->GetRootSize();
|
|
totalSize -= tuple->GetRootSize();
|
|
|
|
for (int i = 0; i < tuple->GetNoAttributes(); i++)
|
|
{
|
|
nextAttr = tuple->GetAttribute(i);
|
|
if(deleteComplete) nextAttr->Finalize();
|
|
for (int j = 0; j < nextAttr->NumOfFLOBs(); j++)
|
|
{
|
|
nextFlob = nextAttr->GetFLOB(j);
|
|
SmiSize fsz = nextFlob->getSize();
|
|
|
|
assert( i >= 0 &&
|
|
(size_t)i < attrSize.size() );
|
|
attrSize[i] -= fsz;
|
|
totalSize -= fsz;
|
|
|
|
if( fsz < Tuple::extensionLimit )
|
|
{
|
|
assert( i >= 0 &&
|
|
(size_t)i < attrExtSize.size() );
|
|
attrExtSize[i] -= fsz;
|
|
totalExtSize -= fsz;
|
|
}
|
|
|
|
if(deleteComplete) nextFlob->destroy();
|
|
}
|
|
}
|
|
}
|
|
return ok;
|
|
}
|
|
|
|
void OrderedRelation::UpdateTuple( Tuple *tuple,
|
|
const vector<int>& changedIndices,
|
|
const vector<Attribute *>& newAttrs ) {
|
|
DeleteTuple(tuple, false);
|
|
tuple->UpdateAttributesOrel(changedIndices, newAttrs );
|
|
|
|
SmiRecord record;
|
|
TupleId extension = tuple->GetTupleId();
|
|
bool rc = tupleFile->InsertRecord(GetKey(tuple, true, extension).GetSmiKey(),
|
|
record);
|
|
assert(rc==true);
|
|
tuple->SaveOrel(&record, lobFileId, totalExtSize, totalSize, attrExtSize,
|
|
attrSize, false, extension);
|
|
record.Finish();
|
|
noTuples++;
|
|
}
|
|
|
|
GenericRelationIterator* OrderedRelation::MakeScan() const {
|
|
#ifdef DEBUG_OREL
|
|
cout << "MakeScan_Orel" << endl;
|
|
#endif
|
|
return new OrderedRelationIterator(this);
|
|
}
|
|
|
|
GenericRelationIterator* OrderedRelation::MakeScan(TupleType* tt) const {
|
|
#ifdef DEBUG_OREL
|
|
cout << "MakeScan(tt)_Orel" << endl;
|
|
#endif
|
|
return new OrderedRelationIterator(this, tt);
|
|
}
|
|
|
|
GenericRelationIterator* OrderedRelation::MakeRangeScan(
|
|
const CompositeKey& from,
|
|
const CompositeKey& to) const{
|
|
#ifdef DEBUG_OREL
|
|
cout << "MakeRangeScan_Orel" << endl;
|
|
#endif
|
|
return new OrderedRelationIterator(this, 0, from, to);
|
|
}
|
|
|
|
|
|
GenericRelationIterator* OrderedRelation::MakeRangeScan(TupleType* tt,
|
|
const CompositeKey& from,
|
|
const CompositeKey& to) const{
|
|
#ifdef DEBUG_OREL
|
|
cout << "MakeRangeScan(tt)_Orel" << endl;
|
|
#endif
|
|
return new OrderedRelationIterator(this, tt, from, to);
|
|
}
|
|
|
|
|
|
bool OrderedRelation::GetTupleFileStats(SmiStatResultType& result) {
|
|
#ifdef DEBUG_OREL
|
|
cout << "GetTupleFileStats_Orel" << endl;
|
|
#endif
|
|
result = tupleFile->GetFileStatistics(SMI_STATS_EAGER);
|
|
std::stringstream fileid;
|
|
fileid << tupleFileId;
|
|
result.push_back(pair<string,string>("FilePurpose",
|
|
"OrderedRelationTupleCoreFile"));
|
|
result.push_back(pair<string,string>("FileId",fileid.str()));
|
|
return true;
|
|
}
|
|
|
|
|
|
bool OrderedRelation::GetLOBFileStats(SmiStatResultType& result) {
|
|
#ifdef DEBUG_OREL
|
|
cout << "GetLOBFileStats_Orel" << endl;
|
|
#endif
|
|
if( !hasLobs ){
|
|
return true;
|
|
}
|
|
SmiRecordFile lobFile(false);
|
|
if( !lobFile.Open( lobFileId ) ){
|
|
return false;
|
|
} else {
|
|
result = lobFile.GetFileStatistics(SMI_STATS_EAGER);
|
|
result.push_back(pair<string,string>("FilePurpose",
|
|
"OrderedRelationTupleLOBFile"));
|
|
std::stringstream fileid;
|
|
fileid << lobFileId;
|
|
result.push_back(pair<string,string>("FileId",fileid.str()));
|
|
}
|
|
if( !lobFile.Close() )
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
CompositeKey OrderedRelation::GetKey(const Tuple* t, const bool appendNumber,
|
|
const TupleId appendix) {
|
|
return CompositeKey(t, keyElement, keyElemType, appendNumber, appendix);
|
|
}
|
|
|
|
CompositeKey OrderedRelation::GetRangeKey(Word& arg, int length, bool upper) {
|
|
Word val;
|
|
Supplier son;
|
|
vector<void*> attributes(length);
|
|
vector<SmiKey::KeyDataType> attrTypes(length);
|
|
for(SmiSize i = 0; (i < (SmiSize)length); i++) {
|
|
son = qp->GetSupplier(arg.addr, i);
|
|
qp->Request(son, val);
|
|
attributes[i] = val.addr;
|
|
attrTypes[i] = keyElemType[i];
|
|
}
|
|
return CompositeKey(attributes, attrTypes, upper);
|
|
}
|
|
|
|
CompositeKey OrderedRelation::GetLowerRangeKey(Word& arg, int length) {
|
|
#ifdef DEBUG_OREL
|
|
cout << "GetLowerRangeKey" << endl;
|
|
#endif
|
|
return GetRangeKey(arg, length, false);
|
|
}
|
|
|
|
CompositeKey OrderedRelation::GetUpperRangeKey(Word& arg, int length) {
|
|
#ifdef DEBUG_OREL
|
|
cout << "GetUpperRangeKey" << endl;
|
|
#endif
|
|
return GetRangeKey(arg, length, true);
|
|
}
|
|
|
|
bool OrderedRelation::GetKeyStructure(ListExpr typeInfo,
|
|
vector<int>& keyElement,
|
|
vector<SmiKey::KeyDataType>& keyElemType) {
|
|
#ifdef DEBUG_OREL
|
|
cout << "GetKeytype_Orel" << endl;
|
|
cout << nl->ToString(typeInfo) << endl;
|
|
#endif
|
|
if(nl->ListLength(typeInfo)!=3 || nl->IsAtom(nl->Second(typeInfo))
|
|
|| nl->ListLength(nl->Second(typeInfo))!=2) return false;
|
|
//(orel(tuple((a1 t1)...(an tn)) (ai1 ai2 ai3))) or
|
|
//(orel(tuple((a1 t1)...(an tn)) ai)) expected
|
|
|
|
ListExpr tupleInfo = nl->Second(nl->Second(typeInfo));
|
|
ListExpr keyInfo = nl->Third(typeInfo);
|
|
int keyCount = 0;
|
|
if(nl->IsAtom(keyInfo)) {
|
|
keyCount = 1;
|
|
} else {
|
|
keyCount = nl->ListLength(keyInfo);
|
|
}
|
|
keyElement.resize(keyCount);
|
|
keyElemType.resize(keyCount);
|
|
int algId, typeId;
|
|
for(int count = 0; count < keyCount; count++) {
|
|
|
|
#ifdef DEBUG_OREL2
|
|
cout << nl->IsAtom(keyInfo) << endl;
|
|
cout << nl->ToString(keyInfo) << endl;
|
|
if(nl->IsAtom(keyInfo)) {
|
|
cout << nl->SymbolValue(keyInfo) << endl;
|
|
}
|
|
#endif
|
|
|
|
string id;
|
|
if(nl->IsAtom(keyInfo)) {
|
|
id = nl->SymbolValue(keyInfo);
|
|
} else {
|
|
id = nl->SymbolValue(nl->First(keyInfo));
|
|
keyInfo = nl->Rest(keyInfo);
|
|
}
|
|
ListExpr tempInfo = tupleInfo;
|
|
bool found = false;
|
|
for(int i=0;!(nl->IsEmpty(tempInfo)||found);i++) {
|
|
ListExpr current = nl->First(tempInfo);
|
|
if(nl->SymbolValue(nl->First(current)) == id) {
|
|
found = true;
|
|
|
|
#ifdef DEBUG_OREL2
|
|
cout << count << '\t' << id << '\t' << i << endl;
|
|
cout << nl->ToString(current) << endl;
|
|
#endif
|
|
|
|
keyElement[count] = i;
|
|
algId = nl->IntValue(nl->First(nl->Second(current)));
|
|
typeId = nl->IntValue(nl->Second(nl->Second(current)));
|
|
string keyTypeString = am->GetTC(algId, typeId)->Name();
|
|
|
|
if (keyTypeString == CcInt::BasicType()) {
|
|
keyElemType[count] = SmiKey::Integer;
|
|
} else if(keyTypeString == LongInt::BasicType()){
|
|
keyElemType[count] = SmiKey::Longint;
|
|
} else if(keyTypeString == CcString::BasicType()) {
|
|
keyElemType[count] = SmiKey::String;
|
|
} else if(keyTypeString == CcReal::BasicType()) {
|
|
keyElemType[count] = SmiKey::Float;
|
|
} else {
|
|
keyElemType[count] = SmiKey::Composite;
|
|
}
|
|
}
|
|
tempInfo = nl->Rest(tempInfo);
|
|
}
|
|
if(!found) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
const SmiBtreeFile* OrderedRelation::GetTupleFile() const {
|
|
return tupleFile;
|
|
}
|
|
|
|
const TupleType* OrderedRelation::GetTupleType() const {
|
|
return tupleType;
|
|
}
|
|
|
|
OrderedRelation::OrderedRelation() {
|
|
#ifdef DEBUG_OREL
|
|
cout << "Konstruktor_Orel" << endl;
|
|
#endif
|
|
}
|
|
|
|
ostream& OrderedRelation::Print(ostream& os) const
|
|
{
|
|
GenericRelationIterator* itORel = MakeScan();
|
|
Tuple* actTuple = itORel->GetNextTuple();
|
|
while (actTuple != 0)
|
|
{
|
|
actTuple->Print(os);
|
|
actTuple->DeleteIfAllowed();
|
|
actTuple = itORel->GetNextTuple();
|
|
}
|
|
return os;
|
|
}
|
|
/*
|
|
4 Operators
|
|
|
|
4.1 orange, oleftrange \& orightrange
|
|
|
|
*/
|
|
enum RangeKind {
|
|
LeftRange,
|
|
RightRange,
|
|
Range
|
|
};
|
|
|
|
/*
|
|
4.1.1 Type Mapping function for orange operators
|
|
|
|
*/
|
|
template<RangeKind rk> ListExpr ORangeTypeMap(ListExpr args) {
|
|
#ifdef DEBUG_OREL
|
|
cout << "RangeTypeMap" << endl;
|
|
#endif
|
|
#ifdef DEBUG_OREL2
|
|
cout << nl->ToString(args) << endl;
|
|
#endif
|
|
string op= rk==LeftRange?"oleftrange":(rk==RightRange?"orightrange":"orange");
|
|
int length = rk==Range?3:2;
|
|
string typelist = "(orel (tuple (a1:t1...an:tn)) (ai1...ain)) x (ti1...tik)";
|
|
if(rk==Range) typelist += " x (ti1...til)";
|
|
if(nl->ListLength(args) != length) {
|
|
ErrorReporter::ReportError("Operator " + op + " expects a list of type "
|
|
+ typelist);
|
|
return nl->TypeError();
|
|
}
|
|
if(!listutils::isOrelDescription(nl->First(args))) {
|
|
ErrorReporter::ReportError("Operator " + op + " expects " + OREL +
|
|
" as first argument");
|
|
return nl->TypeError();
|
|
}
|
|
bool ok = true;
|
|
ListExpr keyList = nl->Third(nl->First(args));
|
|
int t_size = nl->ListLength(keyList);
|
|
vector<string> keyTypes(t_size);
|
|
int count = 0;
|
|
while (!nl->IsEmpty(keyList)) {
|
|
ListExpr attrType;
|
|
ListExpr current = nl->First(keyList);
|
|
keyList = nl->Rest(keyList);
|
|
listutils::findAttribute(nl->Second(nl->Second(nl->First(args))),
|
|
nl->SymbolValue(current), attrType);
|
|
keyTypes[count++] = nl->SymbolValue(attrType);
|
|
}
|
|
ListExpr keyInfo = nl->Second(args);
|
|
if(nl->IsAtom(keyInfo))
|
|
return nl->TypeError();
|
|
length = nl->ListLength(keyInfo);
|
|
if((length==0) || (length > t_size)) {
|
|
ErrorReporter::ReportError("Zero length or too long key list!");
|
|
return nl->TypeError();
|
|
}
|
|
for (int i=0;ok && i<length;i++) {
|
|
ListExpr current = nl->First(keyInfo);
|
|
keyInfo = nl->Rest(keyInfo);
|
|
if(!nl->IsAtom(current))
|
|
return nl->TypeError();
|
|
ok = ok && (keyTypes[i] == nl->SymbolValue(current));
|
|
}
|
|
if(!ok) {
|
|
string tmpStr = rk==Range?"first ":"";
|
|
ErrorReporter::ReportError("The " + tmpStr +
|
|
"range has to follow the typeorder of the " +
|
|
OREL + " key");
|
|
return nl->TypeError();
|
|
}
|
|
if(rk==Range) {
|
|
keyInfo = nl->Third(args);
|
|
if(nl->IsAtom(keyInfo))
|
|
return nl->TypeError();
|
|
length = nl->ListLength(keyInfo);
|
|
if((length==0) || (length > t_size)) {
|
|
ErrorReporter::ReportError("Zero length or too long key list!");
|
|
return nl->TypeError();
|
|
}
|
|
for (int i=0;ok && i<length;i++) {
|
|
ListExpr current = nl->First(keyInfo);
|
|
keyInfo = nl->Rest(keyInfo);
|
|
if(!nl->IsAtom(current))
|
|
return nl->TypeError();
|
|
ok = ok && (keyTypes[i] == nl->SymbolValue(current));
|
|
}
|
|
if(!ok) {
|
|
ErrorReporter::ReportError("The second range has to follow the "
|
|
"typeorder of the " + OREL + " key");
|
|
return nl->TypeError();
|
|
}
|
|
}
|
|
ListExpr appList;
|
|
if(rk==Range) {
|
|
appList = nl->TwoElemList(nl->IntAtom(nl->ListLength(nl->Second(args))),
|
|
nl->IntAtom(nl->ListLength(nl->Third(args))));
|
|
} else {
|
|
appList = nl->OneElemList(nl->IntAtom(nl->ListLength(nl->Second(args))));
|
|
}
|
|
return nl->ThreeElemList(nl->SymbolAtom(Symbol::APPEND()), appList,
|
|
nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()),
|
|
nl->Second(nl->First(args))));
|
|
}
|
|
|
|
#ifndef USE_PROGRESS
|
|
/*
|
|
4.1.2 Value Mapping function of orange operators without progress estimation
|
|
|
|
*/
|
|
|
|
template<RangeKind rk> int ORangeValueMap(Word* args, Word& result, int message,
|
|
Word& local, Supplier s) {
|
|
GenericRelationIterator* rit;
|
|
OrderedRelation* r;
|
|
switch(message) {
|
|
case OPEN: {
|
|
|
|
CompositeKey fromKey;
|
|
CompositeKey toKey;
|
|
int l1 = 0;
|
|
int l2 = 0;
|
|
if(rk==Range) {
|
|
l1 = ((CcInt*)args[3].addr)->GetIntval();
|
|
l2 = ((CcInt*)args[4].addr)->GetIntval();
|
|
} else {
|
|
l1 = ((CcInt*)args[2].addr)->GetIntval();
|
|
}
|
|
r = (OrderedRelation*)args[0].addr;
|
|
if(rk==LeftRange) {
|
|
toKey = r->GetUpperRangeKey(args[1],l1);
|
|
} else if(rk==RightRange) {
|
|
fromKey = r->GetLowerRangeKey(args[1],l1);
|
|
} else if(rk==Range) {
|
|
fromKey = r->GetLowerRangeKey(args[1],l1);
|
|
toKey = r->GetUpperRangeKey(args[2],l2);
|
|
}
|
|
rit = r->MakeRangeScan(fromKey,toKey);
|
|
local.addr = rit;
|
|
return 0;
|
|
}
|
|
case REQUEST:
|
|
rit = (GenericRelationIterator*)local.addr;
|
|
Tuple* t;
|
|
if((t = rit->GetNextTuple())) {
|
|
result.setAddr(t);
|
|
return YIELD;
|
|
}
|
|
return CANCEL;
|
|
break;
|
|
case CLOSE:
|
|
if(local.addr) {
|
|
rit = (GenericRelationIterator*)local.addr;
|
|
delete rit;
|
|
}
|
|
return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#else
|
|
|
|
struct ORangeLocalInfo: public ProgressLocalInfo
|
|
{
|
|
GenericRelationIterator* iter;
|
|
CompositeKey fromKey, toKey;
|
|
bool first;
|
|
int Card;
|
|
int completeCalls;
|
|
int completeReturned;
|
|
};
|
|
|
|
/*
|
|
4.1.3 Value Mapping function of orange operators with progress estimation
|
|
|
|
*/
|
|
template<RangeKind rk> int ORangeValueMap(Word* args, Word& result, int message,
|
|
Word& local, Supplier s) {
|
|
|
|
ORangeLocalInfo* linfo = (ORangeLocalInfo*)local.addr;
|
|
|
|
switch(message) {
|
|
case OPEN: {
|
|
OrderedRelation* orel = (OrderedRelation*)args[0].addr;
|
|
if(!linfo) {
|
|
linfo = new ORangeLocalInfo;
|
|
linfo->completeCalls = 0;
|
|
linfo->completeReturned = 0;
|
|
linfo->iter = 0;
|
|
local = SetWord(linfo);
|
|
|
|
//initialization of sizes
|
|
linfo->total = orel->GetNoTuples();
|
|
linfo->defaultValue = 50;
|
|
linfo->Size = 0;
|
|
linfo->SizeExt = 0;
|
|
linfo->noAttrs = orel->GetTupleType()->GetNoAttributes();
|
|
linfo->attrSize = new double[linfo->noAttrs];
|
|
linfo->attrSizeExt = new double[linfo->noAttrs];
|
|
for(int i=0; i < linfo->noAttrs; i++) {
|
|
linfo->attrSize[i] = orel->GetTotalSize(i) / (linfo->total + 0.001);
|
|
linfo->attrSizeExt[i] = orel->GetTotalExtSize(i) /
|
|
(linfo->total + 0.001);
|
|
linfo->Size += linfo->attrSize[i];
|
|
linfo->SizeExt += linfo->attrSizeExt[i];
|
|
}
|
|
linfo->sizesInitialized = true;
|
|
linfo->sizesChanged = true;
|
|
}
|
|
int l1 = 0;
|
|
int l2 = 0;
|
|
if(rk==Range) {
|
|
l1 = ((CcInt*)args[3].addr)->GetIntval();
|
|
l2 = ((CcInt*)args[4].addr)->GetIntval();
|
|
} else {
|
|
l1 = ((CcInt*)args[2].addr)->GetIntval();
|
|
}
|
|
if(rk==LeftRange) {
|
|
linfo->toKey = orel->GetUpperRangeKey(args[1],l1);
|
|
} else if(rk==RightRange) {
|
|
linfo->fromKey = orel->GetLowerRangeKey(args[1],l1);
|
|
} else if(rk==Range) {
|
|
linfo->fromKey = orel->GetLowerRangeKey(args[1],l1);
|
|
linfo->toKey = orel->GetUpperRangeKey(args[2],l2);
|
|
}
|
|
|
|
SmiKeyRange fromRange, toRange;
|
|
if(rk==RightRange || rk==Range) {
|
|
orel->GetTupleFile()->KeyRange(linfo->fromKey.GetSmiKey(),fromRange);
|
|
linfo->Card = (int)(linfo->total*(1-fromRange.less));
|
|
if(rk==Range) {
|
|
orel->GetTupleFile()->KeyRange(linfo->toKey.GetSmiKey(), toRange);
|
|
linfo->Card = (int)(linfo->total*(1-toRange.greater -
|
|
fromRange.less));
|
|
}
|
|
} else {
|
|
orel->GetTupleFile()->KeyRange(linfo->toKey.GetSmiKey(), toRange);
|
|
linfo->Card = (int)(linfo->total*(1-toRange.greater));
|
|
}
|
|
if(linfo->iter){
|
|
delete linfo->iter;
|
|
}
|
|
linfo->iter = orel->MakeRangeScan(linfo->fromKey,linfo->toKey);
|
|
return 0;
|
|
}
|
|
case REQUEST:
|
|
if(!linfo){
|
|
return CANCEL;
|
|
}
|
|
if(!linfo->iter){
|
|
return CANCEL;
|
|
}
|
|
Tuple* t;
|
|
if((t = linfo->iter->GetNextTuple())) {
|
|
linfo->returned++;
|
|
result.setAddr(t);
|
|
return YIELD;
|
|
}
|
|
return CANCEL;
|
|
|
|
case CLOSE:
|
|
if(linfo) {
|
|
if(linfo->iter){
|
|
delete linfo->iter;
|
|
linfo->iter=0;
|
|
}
|
|
linfo->completeCalls++;
|
|
linfo->completeReturned += linfo->returned;
|
|
linfo->returned = 0;
|
|
|
|
linfo->Card = linfo->completeReturned/linfo->completeCalls;
|
|
}
|
|
return 0;
|
|
|
|
case REQUESTPROGRESS: {
|
|
const double uORange = 0.08; //ms per search
|
|
const double vORange = 0.009; //ms per result tuple
|
|
if(!linfo) return CANCEL;
|
|
|
|
ProgressInfo* p;
|
|
p = (ProgressInfo*)result.addr;
|
|
p->CopySizes(linfo);
|
|
if(linfo->returned > linfo->Card) {
|
|
linfo->Card = (int)(linfo->returned * 1.1);
|
|
if (linfo->Card > linfo->total) {
|
|
linfo->Card = linfo->total;
|
|
}
|
|
}
|
|
p->Card = linfo->Card;
|
|
p->Time = uORange + p->Card*vORange;
|
|
p->Progress = (uORange + linfo->returned*vORange)/p->Time;
|
|
|
|
return YIELD;
|
|
}
|
|
case CLOSEPROGRESS:
|
|
if(linfo) {
|
|
if(linfo->iter){
|
|
delete linfo->iter;
|
|
linfo->iter = 0;
|
|
}
|
|
delete linfo;
|
|
local = SetWord(Address(0));
|
|
}
|
|
return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
4.1.4 Specifications of orange operators
|
|
|
|
*/
|
|
const string OLeftRangeSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
|
"\"Example\" ) "
|
|
"( <text>(orel (tuple(a1:t1 ... an:tn)) (ai1 ai2 ... ain)) x (ti1 ti2) -> "
|
|
"(stream (tuple(a1:t1 ... an:tn)))</text--->"
|
|
"<text>_ oleftrange [key]</text--->"
|
|
"<text>Returns a stream of tuples where each tuple's key is smaller than or "
|
|
"equal as the given key.</text--->"
|
|
"<text>query cities feed oconsume [BevT,Name] oleftrange[100] count</text--->"
|
|
") )";
|
|
|
|
const string ORightRangeSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
|
"\"Example\" ) "
|
|
"( <text>(orel (tuple(a1:t1 ... an:tn)) (ai1 ai2 ... ain)) x (ti1 ti2) -> "
|
|
"(stream (tuple(a1:t1 ... an:tn)))</text--->"
|
|
"<text>_ orightrange [key]</text--->"
|
|
"<text>Returns a stream of tuples where each tuple's key is greater than or "
|
|
"equal as the given key.</text--->"
|
|
"<text>query cities feed oconsume [BevT,Name] orightrange[1000] count"
|
|
"</text--->) )";
|
|
|
|
const string ORangeSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
|
"\"Example\" ) "
|
|
"( <text>(orel (tuple(a1:t1 ... an:tn)) (ai1 ai2 ... ain)) x (ti1 ti2) x "
|
|
"(ti1 ti2 ti3) -> (stream (tuple(a1:t1 ... an:tn)))</text--->"
|
|
"<text>_ orange [leftkey, rightkey]</text--->"
|
|
"<text>Returns a stream of tuples where each tuple's key is between the two "
|
|
"given keys.</text--->"
|
|
"<text>query cities feed oconsume [BevT,Name] orange[500;800] count</text--->"
|
|
") )";
|
|
|
|
Operator oleftrange (
|
|
"oleftrange", // name
|
|
OLeftRangeSpec, // specification
|
|
ORangeValueMap<LeftRange>, // value mapping
|
|
Operator::SimpleSelect, // trivial selection function
|
|
ORangeTypeMap<LeftRange> // type mapping
|
|
);
|
|
|
|
|
|
Operator orightrange (
|
|
"orightrange", // name
|
|
ORightRangeSpec, // specification
|
|
ORangeValueMap<RightRange>, // value mapping
|
|
Operator::SimpleSelect, // trivial selection function
|
|
ORangeTypeMap<RightRange> // type mapping
|
|
);
|
|
|
|
|
|
Operator orange (
|
|
"orange", // name
|
|
ORangeSpec, // specification
|
|
ORangeValueMap<Range>, // value mapping
|
|
Operator::SimpleSelect, // trivial selection function
|
|
ORangeTypeMap<Range> // type mapping
|
|
);
|
|
|
|
/*
|
|
4.2 Operator ~oshortestpathd~
|
|
|
|
We want to use the ordered relation as graph representation. And use this
|
|
specialised ordered relation for shortest path computing.
|
|
|
|
An ordered relation representing the edges of a graph contains for each edge of
|
|
the graph one tuple. Each tuple consists at least of two integer attributes
|
|
identifying the start and end node of the edge, and not less than one
|
|
double attribute representing the costs of the edge.
|
|
The tuples may contain further attributes giving additonal cost informations
|
|
or arbitrary informations for each edge.
|
|
|
|
For the shortest path operation the input relation should be ordered by the
|
|
numbers of the starting nodes at the first and by the end node numbers at the
|
|
second level to reduce the number of page accesses.
|
|
|
|
The operation ~oshortestpathd~ expects an ordered relation with at least three
|
|
attributes (two integer and one double) like described before. Two integers
|
|
identifying the start and the end node, an integer selecting the result
|
|
representation and a cost function mapping the tuple
|
|
values to an real number describing the costs of the edge.
|
|
|
|
The following results can be selected by integer:
|
|
0 shortest path
|
|
1 remaining priority queue at end of computation
|
|
2 visited sections of shortest path search
|
|
3 shortest path tree
|
|
|
|
In case of function result 3 the parameter end node is ignored. And the
|
|
complete shortest path tree from the start node will be computed.
|
|
|
|
In all cases the operation ~oshortestpathd~ extends the original tuples by an
|
|
new attribute seqNo of type int. Describing the sequence number of the edge
|
|
within the path from the start node to the end node (case 0), the number of
|
|
the edges in the priority queue (case 1), the sequence of visiting the edges
|
|
(case 2), and the sequence number the edge was inserted into the shortest path
|
|
tree (case 3).
|
|
|
|
For the path computation Dijkstras Algorithm is used.
|
|
|
|
*/
|
|
|
|
ListExpr OShortestPathDTypeMap(ListExpr args)
|
|
{
|
|
#ifdef DEBUG_OREL
|
|
cout << "OShortestPathDTypeMap" << endl;
|
|
#endif
|
|
#ifdef DEBUG_OREL2
|
|
cout << nl->ToString(args) << endl;
|
|
#endif
|
|
if(nl->ListLength(args) != 5)
|
|
{
|
|
return listutils::typeError("oshortestpathd expects 5 arguments");
|
|
}
|
|
ListExpr orelList = nl->First(args);
|
|
ListExpr startNodeList = nl->Second(args);
|
|
ListExpr endNodeList = nl->Third(args);
|
|
ListExpr resultSelect = nl->Fourth(args);
|
|
ListExpr functionMap = nl->Fifth(args);
|
|
|
|
//Check of first argument
|
|
if(!listutils::isOrelDescription(orelList))
|
|
{
|
|
return listutils::typeError("oshortestpathd expects orel as 1. argument");
|
|
}
|
|
|
|
ListExpr orelTuple = nl->Second(orelList);
|
|
|
|
if (!listutils::isTupleDescription(orelTuple))
|
|
{
|
|
return listutils::typeError("second value of orel is not of type tuple");
|
|
}
|
|
|
|
ListExpr orelAttrList(nl->Second(orelTuple));
|
|
|
|
if (!listutils::isAttrList(orelAttrList))
|
|
{
|
|
return listutils::typeError("Error in orel attrlist.");
|
|
}
|
|
|
|
if (nl->ListLength(orelAttrList) >= 3)
|
|
{
|
|
ListExpr firstAttr = nl->First(orelAttrList);
|
|
|
|
if (nl->ListLength(firstAttr) != 2 ||
|
|
nl->SymbolValue(nl->Second(firstAttr)) != CcInt::BasicType())
|
|
{
|
|
return listutils::typeError("First attribute of orel should be int");
|
|
}
|
|
|
|
ListExpr secondAttr = nl->Second(orelAttrList);
|
|
if (nl->ListLength(secondAttr) != 2 ||
|
|
nl->SymbolValue(nl->Second(secondAttr)) != CcInt::BasicType())
|
|
{
|
|
return listutils::typeError("Second attribute of orel should be int");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return listutils::typeError("orel has less than 3 attributes.");
|
|
}
|
|
|
|
//Check of second argument
|
|
if (!listutils::isSymbol(startNodeList,CcInt::BasicType()))
|
|
{
|
|
return listutils::typeError("Second argument should be int");
|
|
}
|
|
|
|
//Check of third argument
|
|
if (!listutils::isSymbol(endNodeList,CcInt::BasicType()))
|
|
{
|
|
return listutils::typeError("Third argument should be int");
|
|
}
|
|
|
|
//Check of fourth argument
|
|
if (!listutils::isSymbol(resultSelect,CcInt::BasicType()))
|
|
{
|
|
return listutils::typeError("Fourth argument should be int");
|
|
}
|
|
|
|
//Check of fifth argument
|
|
if (!listutils::isMap<1>(functionMap))
|
|
{
|
|
return listutils::typeError("Fourth argument should be a map");
|
|
}
|
|
|
|
ListExpr mapTuple = nl->Second(functionMap);
|
|
|
|
if (!nl->Equal(orelTuple,mapTuple))
|
|
{
|
|
return listutils::typeError("Tuple of map function must match orel tuple");
|
|
}
|
|
|
|
ListExpr mapres = nl->Third(functionMap);
|
|
|
|
if(!listutils::isSymbol(mapres,CcReal::BasicType()))
|
|
{
|
|
return listutils::typeError("Wrong mapping result type for oshortestpathd");
|
|
}
|
|
|
|
//returns stream of tuples like in orel
|
|
NList extendAttrList(nl->TwoElemList(nl->SymbolAtom("SeqNo"),
|
|
nl->SymbolAtom(CcInt::BasicType())));
|
|
NList extOrelAttrList(nl->TheEmptyList());
|
|
|
|
|
|
for (int i = 0; i < nl->ListLength(orelAttrList); i++)
|
|
{
|
|
NList attr(nl->Nth(i+1,orelAttrList));
|
|
extOrelAttrList.append(attr);
|
|
}
|
|
|
|
extOrelAttrList.append(extendAttrList);
|
|
|
|
ListExpr outlist = nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()),
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom(Tuple::BasicType()),
|
|
extOrelAttrList.listExpr()));
|
|
|
|
return outlist;
|
|
}
|
|
|
|
int OShortestPathDValueMap(Word* args, Word& result, int message,
|
|
Word& local, Supplier s)
|
|
{
|
|
#ifdef DEBUG_OREL
|
|
cout << "OShortestPathDValuMap" << endl;
|
|
#endif
|
|
OShortestPathInfo* spi = (OShortestPathInfo*) local.addr;
|
|
|
|
switch(message)
|
|
{
|
|
case OPEN:
|
|
{
|
|
//Create localinfo
|
|
if (spi != 0) delete spi;
|
|
spi = new OShortestPathInfo();
|
|
ListExpr tupleType = GetTupleResultType( s );
|
|
spi->resultSelect = ((CcInt*)args[3].addr)->GetIntval();
|
|
if (spi->resultSelect < 0 || spi->resultSelect > 3)
|
|
{
|
|
cout << "Selected result value does not exist. Enter 0 for shortest";
|
|
cout << " path, 1 for remaining priority queue elements, 2 for visited";
|
|
cout << " edges, 3 for shortest path tree." << endl;
|
|
return 0;
|
|
}
|
|
TupleType* rtt = new TupleType( nl->Second( tupleType ) );
|
|
spi->resTuples = new TupleBuffer((size_t) 64*1024*1024);
|
|
local.setAddr(spi);
|
|
// Check for simplest Case
|
|
int startNode = ((CcInt*)args[1].addr)->GetIntval();
|
|
int endNode = ((CcInt*)args[2].addr)->GetIntval();
|
|
if (spi->resultSelect < 3)
|
|
{
|
|
if (startNode == endNode)
|
|
{
|
|
//source and target node are equal no path
|
|
rtt->DeleteIfAllowed();
|
|
rtt = 0;
|
|
return 0;
|
|
}
|
|
}
|
|
//Shortest Path Evaluation
|
|
//Get edge Tuples for StartNode
|
|
OrderedRelation* orel = (OrderedRelation*)args[0].addr;
|
|
OrderedRelationIterator* orelIt = 0;
|
|
vector<void*> attributes(2);
|
|
vector<SmiKey::KeyDataType> kElems(2);
|
|
SmiKey test((int32_t) 0);
|
|
kElems[0] = test.GetType();
|
|
kElems[1] = test.GetType();
|
|
int toNode = startNode;
|
|
//Init priority Queue
|
|
DbArray<PQEntryOrel>* spTree = new DbArray<PQEntryOrel>(0);
|
|
NodeEntryTree* visitedNodes = new NodeEntryTree(0);
|
|
PQueueOrel* prioQ = new PQueueOrel(0);
|
|
prioQ->Insert(PQEntryOrel(startNode,
|
|
-1,
|
|
0.0,
|
|
0.0),
|
|
visitedNodes, spTree);
|
|
bool found = false;
|
|
PQEntryOrel* actPQEntry = 0;
|
|
double dist = 0.0;
|
|
Tuple* actTuple = 0;
|
|
CcInt* minNodeId = new CcInt(true,0);
|
|
CcInt* maxNodeId = new CcInt(true,numeric_limits<int>::max());
|
|
//Search shortest path
|
|
while(!prioQ->IsEmpty() && !found)
|
|
{
|
|
actPQEntry = prioQ->GetAndDeleteMin(visitedNodes);
|
|
if (spi->resultSelect < 3 && actPQEntry->nodeNumber == endNode)
|
|
{
|
|
found = true;
|
|
}
|
|
else
|
|
{
|
|
CcInt* actNodeInt = new CcInt(true,actPQEntry->nodeNumber);
|
|
|
|
attributes[0] = actNodeInt;
|
|
attributes[1] = minNodeId;
|
|
CompositeKey actNodeLower(attributes,kElems,false);
|
|
attributes[1] = maxNodeId;
|
|
CompositeKey actNodeUpper(attributes,kElems,true);
|
|
orelIt =
|
|
(OrderedRelationIterator*) orel->MakeRangeScan(actNodeLower,
|
|
actNodeUpper);
|
|
actTuple = orelIt->GetNextTuple();
|
|
while(actTuple != 0)
|
|
{
|
|
toNode = ((CcInt*)actTuple->GetAttribute(1))->GetIntval();
|
|
if (actPQEntry->nodeNumber != toNode)
|
|
{
|
|
ArgVectorPointer funArgs = qp->Argument(args[4].addr);
|
|
Word funResult;
|
|
((*funArgs)[0]).setAddr(actTuple);
|
|
qp->Request(args[4].addr,funResult);
|
|
double edgeCost = ((CcReal*)funResult.addr)->GetRealval();
|
|
if (edgeCost < 0.0)
|
|
{
|
|
cerr << "Found negativ edge cost computation aborted." << endl;
|
|
actTuple->DeleteIfAllowed();
|
|
actTuple = 0;
|
|
actNodeInt->DeleteIfAllowed();
|
|
delete orelIt;
|
|
orelIt = 0;
|
|
delete actPQEntry;
|
|
actPQEntry = 0;
|
|
minNodeId->DeleteIfAllowed();
|
|
maxNodeId->DeleteIfAllowed();
|
|
attributes.clear();
|
|
kElems.clear();
|
|
prioQ->Clear();
|
|
prioQ->Destroy();
|
|
delete prioQ;
|
|
visitedNodes->Destroy();
|
|
delete visitedNodes;
|
|
spTree->Destroy();
|
|
delete spTree;
|
|
rtt->DeleteIfAllowed();
|
|
rtt = 0;
|
|
return 0;
|
|
}
|
|
dist = actPQEntry->distFromStart + edgeCost;
|
|
prioQ->Insert(PQEntryOrel(toNode,
|
|
actPQEntry->nodeNumber,
|
|
dist,
|
|
dist),
|
|
visitedNodes,spTree);
|
|
}
|
|
actTuple->DeleteIfAllowed();
|
|
actTuple = 0;
|
|
actTuple = orelIt->GetNextTuple();
|
|
}
|
|
if (actTuple != 0)
|
|
{
|
|
actTuple->DeleteIfAllowed();
|
|
actTuple = 0;
|
|
}
|
|
actNodeInt->DeleteIfAllowed();
|
|
delete orelIt;
|
|
orelIt = 0;
|
|
delete actPQEntry;
|
|
actPQEntry = 0;
|
|
}
|
|
}
|
|
minNodeId->DeleteIfAllowed();
|
|
maxNodeId->DeleteIfAllowed();
|
|
if (spi->resultSelect < 3 && !found) //no path exists
|
|
{
|
|
cout << "no path exists" << endl;
|
|
attributes.clear();
|
|
kElems.clear();
|
|
prioQ->Clear();
|
|
prioQ->Destroy();
|
|
delete prioQ;
|
|
visitedNodes->Destroy();
|
|
delete visitedNodes;
|
|
spTree->Destroy();
|
|
delete spTree;
|
|
rtt->DeleteIfAllowed();
|
|
rtt = 0;
|
|
return 0;
|
|
}
|
|
else //Shortest Path found write result Relation
|
|
{
|
|
switch(spi->resultSelect)
|
|
{
|
|
case 0: // shortest path
|
|
{
|
|
int actEntryPos = visitedNodes->Find(actPQEntry->nodeNumber);
|
|
TreeEntry te = visitedNodes->GetTreeEntry(actEntryPos);
|
|
NodeEntry nE = te.GetNodeEntry();
|
|
delete actPQEntry;
|
|
actPQEntry = 0;
|
|
CcInt* startNodeInt = new CcInt(true,nE.beforeNodeId);
|
|
CcInt* endNodeInt = new CcInt(true,nE.nodeId);
|
|
attributes[0] = startNodeInt;
|
|
attributes[1] = endNodeInt;
|
|
CompositeKey actNodeKeyLower(attributes,kElems,false);
|
|
CompositeKey actNodeKeyUpper(attributes,kElems,true);
|
|
Tuple *newTuple = 0;
|
|
orelIt =
|
|
(OrderedRelationIterator*) orel->MakeRangeScan(actNodeKeyLower,
|
|
actNodeKeyUpper);
|
|
actTuple = orelIt->GetNextTuple();
|
|
found = false;
|
|
while (!found && actTuple != 0)
|
|
{
|
|
newTuple = new Tuple( rtt );
|
|
int i = 0;
|
|
while( i < actTuple->GetNoAttributes())
|
|
{
|
|
newTuple->CopyAttribute(i, actTuple,i);
|
|
i++;
|
|
}
|
|
CcInt* noOfNodes = new CcInt(true, 0);
|
|
spi->seqNoAttrIndex = i;
|
|
newTuple->PutAttribute(i,noOfNodes);
|
|
spi->resTuples->AppendTuple(newTuple);
|
|
if (newTuple != 0)
|
|
{
|
|
newTuple->DeleteIfAllowed();
|
|
newTuple = 0;
|
|
}
|
|
if (nE.GetBeforeNodeId() != startNode)
|
|
actEntryPos = visitedNodes->Find(nE.GetBeforeNodeId());
|
|
else
|
|
found = true;
|
|
if (!found)
|
|
{
|
|
te = visitedNodes->GetTreeEntry(actEntryPos);
|
|
nE = te.GetNodeEntry();
|
|
startNodeInt->DeleteIfAllowed();
|
|
endNodeInt->DeleteIfAllowed();
|
|
startNodeInt = new CcInt(true,nE.beforeNodeId);
|
|
endNodeInt = new CcInt(true,nE.nodeId);
|
|
attributes[0] = startNodeInt;
|
|
attributes[1] = endNodeInt;
|
|
CompositeKey actNodeKeyLower(attributes,kElems,false);
|
|
CompositeKey actNodeKeyUpper(attributes,kElems,true);
|
|
delete orelIt;
|
|
orelIt = (OrderedRelationIterator*)
|
|
orel->MakeRangeScan(actNodeKeyLower, actNodeKeyUpper);
|
|
if (actTuple != 0)
|
|
{
|
|
actTuple->DeleteIfAllowed();
|
|
actTuple = 0;
|
|
}
|
|
actTuple = orelIt->GetNextTuple();
|
|
}
|
|
}
|
|
if (startNodeInt != 0)
|
|
{
|
|
startNodeInt->DeleteIfAllowed();
|
|
startNodeInt = 0;
|
|
}
|
|
if (endNodeInt != 0)
|
|
{
|
|
endNodeInt->DeleteIfAllowed();
|
|
endNodeInt = 0;
|
|
}
|
|
if (actTuple != 0)
|
|
{
|
|
actTuple->DeleteIfAllowed();
|
|
actTuple = 0;
|
|
}
|
|
delete orelIt;
|
|
orelIt = 0;
|
|
break;
|
|
}
|
|
|
|
case 1: //Remaining elements in priority queue
|
|
{
|
|
delete actPQEntry;
|
|
actPQEntry = 0;
|
|
for (int i = 0; i < prioQ->firstFree; i++)
|
|
{
|
|
actPQEntry = prioQ->GetAndDeleteMin(visitedNodes);
|
|
if (actPQEntry == 0) break;
|
|
CcInt* startNodeInt =
|
|
new CcInt(true,actPQEntry->beforeNodeNumber);
|
|
CcInt* endNodeInt = new CcInt(true,actPQEntry->nodeNumber);
|
|
attributes[0] = startNodeInt;
|
|
attributes[1] = endNodeInt;
|
|
CompositeKey actNodeKeyLower(attributes,kElems,false);
|
|
CompositeKey actNodeKeyUpper(attributes,kElems,true);
|
|
orelIt =
|
|
(OrderedRelationIterator*) orel->MakeRangeScan(actNodeKeyLower,
|
|
actNodeKeyUpper);
|
|
actTuple = orelIt->GetNextTuple();
|
|
Tuple* newTuple = new Tuple( rtt );
|
|
int j = 0;
|
|
while( j < actTuple->GetNoAttributes())
|
|
{
|
|
newTuple->CopyAttribute(j, actTuple,j);
|
|
j++;
|
|
}
|
|
CcInt* noOfNodes = new CcInt(true, i+1);
|
|
newTuple->PutAttribute(j, noOfNodes);
|
|
spi->resTuples->AppendTuple(newTuple);
|
|
if (newTuple != 0)
|
|
{
|
|
newTuple->DeleteIfAllowed();
|
|
newTuple = 0;
|
|
}
|
|
if (startNodeInt != 0)
|
|
{
|
|
startNodeInt->DeleteIfAllowed();
|
|
startNodeInt = 0;
|
|
}
|
|
if (endNodeInt != 0)
|
|
{
|
|
endNodeInt->DeleteIfAllowed();
|
|
endNodeInt = 0;
|
|
}
|
|
if (actTuple != 0)
|
|
{
|
|
actTuple->DeleteIfAllowed();
|
|
actTuple = 0;
|
|
}
|
|
delete orelIt;
|
|
orelIt = 0;
|
|
if (actPQEntry != 0)
|
|
{
|
|
delete actPQEntry;
|
|
actPQEntry = 0;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case 2: //visited sections
|
|
{
|
|
PQEntryOrel pqElem;
|
|
for (int i = 1; i < spTree->Size(); i++)
|
|
{
|
|
spTree->Get(i,pqElem);
|
|
CcInt* startNodeInt = new CcInt(true,pqElem.beforeNodeNumber);
|
|
CcInt* endNodeInt = new CcInt(true,pqElem.nodeNumber);
|
|
attributes[0] = startNodeInt;
|
|
attributes[1] = endNodeInt;
|
|
CompositeKey actNodeKeyLower(attributes,kElems,false);
|
|
CompositeKey actNodeKeyUpper(attributes,kElems,true);
|
|
orelIt =
|
|
(OrderedRelationIterator*) orel->MakeRangeScan(actNodeKeyLower,
|
|
actNodeKeyUpper);
|
|
actTuple = orelIt->GetNextTuple();
|
|
Tuple* newTuple = new Tuple( rtt );
|
|
int j = 0;
|
|
while( j < actTuple->GetNoAttributes())
|
|
{
|
|
newTuple->CopyAttribute(j, actTuple,j);
|
|
j++;
|
|
}
|
|
CcInt* noOfNodes = new CcInt(true, i);
|
|
newTuple->PutAttribute(j, noOfNodes);
|
|
spi->resTuples->AppendTuple(newTuple);
|
|
if (newTuple != 0)
|
|
{
|
|
newTuple->DeleteIfAllowed();
|
|
newTuple = 0;
|
|
}
|
|
if (startNodeInt != 0)
|
|
{
|
|
startNodeInt->DeleteIfAllowed();
|
|
startNodeInt = 0;
|
|
}
|
|
if (endNodeInt != 0)
|
|
{
|
|
endNodeInt->DeleteIfAllowed();
|
|
endNodeInt = 0;
|
|
}
|
|
if (actTuple != 0)
|
|
{
|
|
actTuple->DeleteIfAllowed();
|
|
actTuple = 0;
|
|
}
|
|
delete orelIt;
|
|
orelIt = 0;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case 3: //shortest path tree
|
|
{
|
|
NodeEntry actElem;
|
|
for (int i = 1; i < visitedNodes->fFree; i++)
|
|
{
|
|
actElem = visitedNodes->GetTreeEntry(i).GetNodeEntry();
|
|
CcInt* startNodeInt = new CcInt(true,actElem.GetBeforeNodeId());
|
|
CcInt* endNodeInt = new CcInt(true,actElem.GetNodeId());
|
|
attributes[0] = startNodeInt;
|
|
attributes[1] = endNodeInt;
|
|
CompositeKey actNodeKeyLower(attributes,kElems,false);
|
|
CompositeKey actNodeKeyUpper(attributes,kElems,true);
|
|
orelIt =
|
|
(OrderedRelationIterator*) orel->MakeRangeScan(actNodeKeyLower,
|
|
actNodeKeyUpper);
|
|
actTuple = orelIt->GetNextTuple();
|
|
Tuple* newTuple = new Tuple( rtt );
|
|
int j = 0;
|
|
while( j < actTuple->GetNoAttributes())
|
|
{
|
|
newTuple->CopyAttribute(j, actTuple,j);
|
|
j++;
|
|
}
|
|
CcInt* noOfNodes = new CcInt(true, i);
|
|
newTuple->PutAttribute(j, noOfNodes);
|
|
spi->resTuples->AppendTuple(newTuple);
|
|
|
|
if (newTuple != 0)
|
|
{
|
|
newTuple->DeleteIfAllowed();
|
|
newTuple = 0;
|
|
}
|
|
if (startNodeInt != 0)
|
|
{
|
|
startNodeInt->DeleteIfAllowed();
|
|
startNodeInt = 0;
|
|
}
|
|
if (endNodeInt != 0)
|
|
{
|
|
endNodeInt->DeleteIfAllowed();
|
|
endNodeInt = 0;
|
|
}
|
|
if (actTuple != 0)
|
|
{
|
|
actTuple->DeleteIfAllowed();
|
|
actTuple = 0;
|
|
}
|
|
delete orelIt;
|
|
orelIt = 0;
|
|
}
|
|
break;
|
|
}
|
|
|
|
default: //should never been reached;
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (actPQEntry != 0)
|
|
{
|
|
delete actPQEntry;
|
|
actPQEntry = 0;
|
|
}
|
|
if (actTuple != 0)
|
|
{
|
|
actTuple->DeleteIfAllowed();
|
|
actTuple = 0;
|
|
}
|
|
rtt->DeleteIfAllowed();
|
|
rtt = 0;
|
|
attributes.clear();
|
|
kElems.clear();
|
|
prioQ->Clear();
|
|
prioQ->Destroy();
|
|
delete prioQ;
|
|
visitedNodes->Destroy();
|
|
delete visitedNodes;
|
|
spTree->Destroy();
|
|
delete spTree;
|
|
spTree = 0;
|
|
spi->counter = spi->resTuples->GetNoTuples();
|
|
spi->iter = spi->resTuples->MakeScan();
|
|
return 0;
|
|
break;
|
|
}
|
|
|
|
case REQUEST:
|
|
{
|
|
if (spi != 0 && spi->resTuples != 0 && spi->iter != 0)
|
|
{
|
|
Tuple* res = spi->iter->GetNextTuple();
|
|
if (res != 0)
|
|
{
|
|
if (spi->resultSelect == 0)
|
|
{
|
|
res->PutAttribute( spi->seqNoAttrIndex,
|
|
new CcInt (true, spi->counter));
|
|
spi->counter--;
|
|
result.setAddr(res);
|
|
return YIELD;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
if (spi->resultSelect > 0 && spi->resultSelect < 4)
|
|
{
|
|
result.setAddr(res);
|
|
return YIELD;
|
|
break;
|
|
}
|
|
else
|
|
return CANCEL;
|
|
}
|
|
}
|
|
}
|
|
return CANCEL;
|
|
break;
|
|
}
|
|
|
|
case CLOSE:
|
|
{
|
|
if (spi != 0)
|
|
{
|
|
delete spi->iter;
|
|
spi->iter = 0;
|
|
delete spi->resTuples;
|
|
spi->resTuples = 0;
|
|
delete spi;
|
|
spi = 0;
|
|
local.setAddr(0);
|
|
}
|
|
return 0;
|
|
break;
|
|
}
|
|
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
const string OShortestPathDSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
|
"\"Example\" ) "
|
|
"( <text>(orel(tuple(a1:t1 ... an:tn))(ai1 ai2 ... ain)) x ti1 x ti2 x int"
|
|
" x (tuple->real) -> "
|
|
"(stream (tuple(a1:t1 ... an:tn SeqNo: int)))</text--->"
|
|
"<text>_ oshortestpathd [int,int,int;fun]</text--->"
|
|
"<text>The operation ~oshortestpathd~ expects an ordered relation "
|
|
"representing the edges of a graph. Each edge of the graph is "
|
|
"represented by one tuple consisting at least of two integer attributes "
|
|
"identifying the start and end node of the edge, and not less than one real "
|
|
"attribute representing the costs of the edge. "
|
|
"The tuples may contain further "
|
|
"attributes giving additional cost information or arbitrary informations for "
|
|
"each edge. Besides this ordered relation, the operator expects the start and"
|
|
" end node identifiers and a selecting int value choosing the return value."
|
|
" In case of 0 the operator"
|
|
" returns the shortest path from node ti1 to ti2 as a stream of tuples"
|
|
" where each tuple is extended by a sequence number telling which is the"
|
|
" place of the tuple in the shortest path. In case of 1 the operator returns"
|
|
" the stream of tuples which are in the priority queue at the end of the"
|
|
" operation extended by their number in the queue. In case of 2 the operator"
|
|
" returns the stream of tuples which have been touched by the operator. In"
|
|
" case of 3 the operator returns a stream of tuples giving the shortest path"
|
|
" tree from the start node (The target node will be ignored in case 3)."
|
|
" The last parameter is a cost function for the edges."
|
|
" For the path computation Dijkstras Algorithm is used.</text--->"
|
|
"<text>query otest oshortestpathd[1, 1, 0; .Cost] consume</text--->) )";
|
|
|
|
Operator oshortestpathd (
|
|
"oshortestpathd", // name
|
|
OShortestPathDSpec, // specification
|
|
OShortestPathDValueMap, // value mapping
|
|
Operator::SimpleSelect, // trivial selection function
|
|
OShortestPathDTypeMap // type mapping
|
|
);
|
|
|
|
/*
|
|
4.2 Operator ~oshortestpatha~
|
|
|
|
We want to use the ordered relation as graph representation. And use this
|
|
specialised ordered relation for shortest path computing.
|
|
|
|
An ordered relation representing the edges of a graph contains for each edge of
|
|
the graph one tuple. Each tuple consists at least of two integer attributes
|
|
identifying the start and end node of the edge, and not less than two
|
|
double attributes representing the costs of the edge, and the distance function
|
|
to the target. For weight computation in Astar-Algorithm.
|
|
The tuples may contain further attributes giving additonal cost informations
|
|
or arbitrary informations for each edge.
|
|
|
|
For the shortest path operation the input relation should be ordered by the
|
|
numbers of the starting nodes at the first and by the end node numbers at the
|
|
second level to reduce the number of page accesses.
|
|
|
|
The operation ~oshortestpatha~ expects an ordered relation with at least four
|
|
attributes (two integer and two double) like described before. Two integers
|
|
identifying the start and the end node, an integer selecting the result
|
|
representation, a cost function mapping the tuple values to an real number
|
|
describing the costs of the edge, and a cost function mapping the tuple values
|
|
to an real number describing the costs from the end of the edge to the target.
|
|
|
|
The following results can be selected by integer:
|
|
0 shortest path
|
|
1 remaining priority queue at end of computation
|
|
2 visited sections of shortest path search
|
|
3 shortest path tree detected before target node was reached.
|
|
|
|
In all cases the operation ~oshortestpatha~ extends the original tuples by an
|
|
new attribute seqNo of type int. Describing the sequence number of the edge
|
|
within the path from the start node to the end node (case 0), the number of
|
|
the edges in the priority queue (case 1), the sequence of visited edges
|
|
(case 2), and the sequence number the edge was inserted into the shortest path
|
|
tree (case 3).
|
|
|
|
For the path computation AStar-Algorithm is used.
|
|
|
|
*/
|
|
|
|
ListExpr OShortestPathATypeMap(ListExpr args)
|
|
{
|
|
#ifdef DEBUG_OREL
|
|
cout << "OShortestPathATypeMap" << endl;
|
|
#endif
|
|
#ifdef DEBUG_OREL2
|
|
cout << nl->ToString(args) << endl;
|
|
#endif
|
|
if(nl->ListLength(args) != 6)
|
|
{
|
|
return listutils::typeError("oshortestpatha expects 5 arguments");
|
|
}
|
|
ListExpr orelList = nl->First(args);
|
|
ListExpr startNodeList = nl->Second(args);
|
|
ListExpr endNodeList = nl->Third(args);
|
|
ListExpr selectFunList = nl->Fourth(args);
|
|
ListExpr functionDistMap = nl->Fifth(args);
|
|
ListExpr functionWeightMap = nl->Sixth(args);
|
|
|
|
//Check of first argument
|
|
if(!listutils::isOrelDescription(orelList))
|
|
{
|
|
return listutils::typeError("oshortestpatha expects orel as 1. argument");
|
|
}
|
|
|
|
ListExpr orelTuple = nl->Second(orelList);
|
|
|
|
if (!listutils::isTupleDescription(orelTuple))
|
|
{
|
|
return listutils::typeError("second value of orel is not of type tuple");
|
|
}
|
|
|
|
ListExpr orelAttrList(nl->Second(orelTuple));
|
|
|
|
if (!listutils::isAttrList(orelAttrList))
|
|
{
|
|
return listutils::typeError("Error in orel attrlist.");
|
|
}
|
|
|
|
if (nl->ListLength(orelAttrList) >= 4)
|
|
{
|
|
ListExpr firstAttr = nl->First(orelAttrList);
|
|
|
|
if (nl->ListLength(firstAttr) != 2 ||
|
|
nl->SymbolValue(nl->Second(firstAttr)) != CcInt::BasicType())
|
|
{
|
|
return listutils::typeError("First attribute of orel should be int");
|
|
}
|
|
|
|
ListExpr secondAttr = nl->Second(orelAttrList);
|
|
if (nl->ListLength(secondAttr) != 2 ||
|
|
nl->SymbolValue(nl->Second(secondAttr)) != CcInt::BasicType())
|
|
{
|
|
return listutils::typeError("Second attribute of orel should be int");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return listutils::typeError("orel has less than 4 attributes.");
|
|
}
|
|
|
|
//Check of second argument
|
|
if (!listutils::isSymbol(startNodeList,CcInt::BasicType()))
|
|
{
|
|
return listutils::typeError("Second argument should be int");
|
|
}
|
|
|
|
//Check of third argument
|
|
if (!listutils::isSymbol(endNodeList,CcInt::BasicType()))
|
|
{
|
|
return listutils::typeError("Third argument should be int");
|
|
}
|
|
|
|
//Check of fourth argument
|
|
if (!listutils::isSymbol(selectFunList,CcInt::BasicType()))
|
|
{
|
|
return listutils::typeError("Fourth argument should be int");
|
|
}
|
|
|
|
// check of fifth argument
|
|
if (!listutils::isMap<1>(functionDistMap))
|
|
{
|
|
return listutils::typeError("Fifth argument should be a map");
|
|
}
|
|
|
|
ListExpr mapTuple1 = nl->Second(functionDistMap);
|
|
|
|
if (!nl->Equal(orelTuple,mapTuple1))
|
|
{
|
|
return listutils::typeError("Tuple of map function must match orel tuple");
|
|
}
|
|
|
|
ListExpr mapres1 = nl->Third(functionDistMap);
|
|
|
|
if(!listutils::isSymbol(mapres1,CcReal::BasicType()))
|
|
{
|
|
return listutils::typeError("Wrong mapping result type for oshortestpatha");
|
|
}
|
|
|
|
// check of sixth argument
|
|
if (!listutils::isMap<1>(functionWeightMap))
|
|
{
|
|
return listutils::typeError("Sixth argument should be a map");
|
|
}
|
|
|
|
ListExpr mapTuple2 = nl->Second(functionWeightMap);
|
|
|
|
if (!nl->Equal(orelTuple,mapTuple2))
|
|
{
|
|
return listutils::typeError("Tuple of map function must match orel tuple");
|
|
}
|
|
|
|
ListExpr mapres2 = nl->Third(functionWeightMap);
|
|
|
|
if(!listutils::isSymbol(mapres2,CcReal::BasicType()))
|
|
{
|
|
return listutils::typeError("Wrong mapping result type for oshortestpath");
|
|
}
|
|
|
|
//returns stream of tuples like in orel
|
|
NList extendAttrList(nl->TwoElemList(nl->SymbolAtom("SeqNo"),
|
|
nl->SymbolAtom(CcInt::BasicType())));
|
|
NList extOrelAttrList(nl->TheEmptyList());
|
|
|
|
|
|
for (int i = 0; i < nl->ListLength(orelAttrList); i++)
|
|
{
|
|
NList attr(nl->Nth(i+1,orelAttrList));
|
|
extOrelAttrList.append(attr);
|
|
#ifdef DEBUG_OREL2
|
|
cout << "extOrelAttrList: ";
|
|
extOrelAttrList.writeAsStringTo(cout);
|
|
cout << endl;
|
|
#endif
|
|
}
|
|
|
|
extOrelAttrList.append(extendAttrList);
|
|
|
|
|
|
ListExpr outlist = nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()),
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom(Tuple::BasicType()),
|
|
extOrelAttrList.listExpr()));
|
|
|
|
return outlist;
|
|
}
|
|
|
|
int OShortestPathAValueMap(Word* args, Word& result, int message,
|
|
Word& local, Supplier s)
|
|
{
|
|
#ifdef DEBUG_OREL
|
|
cout << "OShortestPathAValuMap" << endl;
|
|
#endif
|
|
OShortestPathInfo* spi = (OShortestPathInfo*) local.addr;
|
|
|
|
switch(message)
|
|
{
|
|
case OPEN:
|
|
{
|
|
//Create localinfo
|
|
if (spi != 0) delete spi;
|
|
spi = new OShortestPathInfo();
|
|
spi->resultSelect = ((CcInt*)args[3].addr)->GetIntval();
|
|
if (spi->resultSelect < 0 || spi->resultSelect > 3)
|
|
{
|
|
cout << "Selected result value does not exist. Enter 0 for shortest";
|
|
cout << " path, 1 for remaining priority queue elements, 2 for visited";
|
|
cout << " edges, 3 for shortest path tree till target reached." << endl;
|
|
return 0;
|
|
}
|
|
ListExpr tupleType = GetTupleResultType( s );
|
|
TupleType* rtt = new TupleType( nl->Second( tupleType ) );
|
|
spi->resTuples = new TupleBuffer((size_t) 64*1024*1024);
|
|
local.setAddr(spi);
|
|
// Check for simplest Case
|
|
int startNode = ((CcInt*)args[1].addr)->GetIntval();
|
|
int endNode = ((CcInt*)args[2].addr)->GetIntval();
|
|
if (startNode == endNode)
|
|
{
|
|
//source and target node are equal no path
|
|
rtt->DeleteIfAllowed();
|
|
rtt = 0;
|
|
return 0;
|
|
}
|
|
|
|
//Shortest Path Evaluation
|
|
//Get edge Tuples for StartNode
|
|
OrderedRelation* orel = (OrderedRelation*)args[0].addr;
|
|
OrderedRelationIterator* orelIt = 0;
|
|
vector<void*> attributes(2);
|
|
vector<SmiKey::KeyDataType> kElems(2);
|
|
SmiKey test((int32_t) 0);
|
|
kElems[0] = test.GetType();
|
|
kElems[1] = test.GetType();
|
|
int toNode = startNode;
|
|
//Init priority Queue
|
|
DbArray<PQEntryOrel>* spTree = new DbArray<PQEntryOrel>(0);
|
|
NodeEntryTree* visitedNodes = new NodeEntryTree(0);
|
|
PQueueOrel* prioQ = new PQueueOrel(0);
|
|
prioQ->Insert(PQEntryOrel(startNode,
|
|
-1,
|
|
0.0,
|
|
0.0),
|
|
visitedNodes,spTree);
|
|
bool found = false;
|
|
PQEntryOrel* actPQEntry = 0;
|
|
double dist = 0.0;
|
|
Tuple* actTuple = 0;
|
|
CcInt* minNodeId = new CcInt(true,0);
|
|
CcInt* maxNodeId = new CcInt(true,numeric_limits<int>::max());
|
|
//Search shortest path
|
|
while(!prioQ->IsEmpty() && !found)
|
|
{
|
|
actPQEntry = prioQ->GetAndDeleteMin(visitedNodes);
|
|
if (actPQEntry->nodeNumber == endNode)
|
|
{
|
|
found = true;
|
|
}
|
|
else
|
|
{
|
|
CcInt* actNodeInt = new CcInt(true,actPQEntry->nodeNumber);
|
|
|
|
attributes[0] = actNodeInt;
|
|
attributes[1] = minNodeId;
|
|
CompositeKey actNodeLower(attributes,kElems,false);
|
|
attributes[1] = maxNodeId;
|
|
CompositeKey actNodeUpper(attributes,kElems,true);
|
|
orelIt =
|
|
(OrderedRelationIterator*) orel->MakeRangeScan(actNodeLower,
|
|
actNodeUpper);
|
|
actTuple = orelIt->GetNextTuple();
|
|
while(actTuple != 0)
|
|
{
|
|
toNode = ((CcInt*)actTuple->GetAttribute(1))->GetIntval();
|
|
if (actPQEntry->nodeNumber != toNode)
|
|
{
|
|
ArgVectorPointer funArgs1 = qp->Argument(args[4].addr);
|
|
Word funResult1;
|
|
((*funArgs1)[0]).setAddr(actTuple);
|
|
qp->Request(args[4].addr,funResult1);
|
|
double edgeCost = ((CcReal*)funResult1.addr)->GetRealval();
|
|
if (edgeCost < 0.0)
|
|
{
|
|
cerr << "Found negativ edge cost computation aborted." << endl;
|
|
actTuple->DeleteIfAllowed();
|
|
actTuple = 0;
|
|
actNodeInt->DeleteIfAllowed();
|
|
delete orelIt;
|
|
orelIt = 0;
|
|
delete actPQEntry;
|
|
actPQEntry = 0;
|
|
minNodeId->DeleteIfAllowed();
|
|
maxNodeId->DeleteIfAllowed();
|
|
attributes.clear();
|
|
kElems.clear();
|
|
prioQ->Clear();
|
|
prioQ->Destroy();
|
|
delete prioQ;
|
|
visitedNodes->Destroy();
|
|
delete visitedNodes;
|
|
spTree->Destroy();
|
|
delete spTree;
|
|
rtt->DeleteIfAllowed();
|
|
rtt = 0;
|
|
return 0;
|
|
}
|
|
dist = actPQEntry->distFromStart + edgeCost;
|
|
ArgVectorPointer funArgs2 = qp->Argument(args[5].addr);
|
|
Word funResult2;
|
|
((*funArgs2)[0]).setAddr(actTuple);
|
|
qp->Request(args[5].addr,funResult2);
|
|
double restCost = ((CcReal*)funResult2.addr)->GetRealval();
|
|
if (restCost < 0) restCost = 0;
|
|
double prioVal = dist + restCost;
|
|
prioQ->Insert(PQEntryOrel(toNode,
|
|
actPQEntry->nodeNumber,
|
|
dist,
|
|
prioVal),
|
|
visitedNodes,spTree);
|
|
}
|
|
actTuple->DeleteIfAllowed();
|
|
actTuple = 0;
|
|
actTuple = orelIt->GetNextTuple();
|
|
}
|
|
if (actTuple != 0)
|
|
{
|
|
actTuple->DeleteIfAllowed();
|
|
actTuple = 0;
|
|
}
|
|
actNodeInt->DeleteIfAllowed();
|
|
delete orelIt;
|
|
orelIt = 0;
|
|
delete actPQEntry;
|
|
actPQEntry = 0;
|
|
}
|
|
}
|
|
minNodeId->DeleteIfAllowed();
|
|
maxNodeId->DeleteIfAllowed();
|
|
if (!found) //no path exists
|
|
{
|
|
cout << "no path exists" << endl;
|
|
attributes.clear();
|
|
kElems.clear();
|
|
prioQ->Clear();
|
|
prioQ->Destroy();
|
|
delete prioQ;
|
|
visitedNodes->Destroy();
|
|
delete visitedNodes;
|
|
spTree->Destroy();
|
|
delete spTree;
|
|
rtt->DeleteIfAllowed();
|
|
if (actPQEntry != 0)
|
|
{
|
|
delete actPQEntry;
|
|
actPQEntry = 0;
|
|
}
|
|
rtt = 0;
|
|
return 0;
|
|
}
|
|
else //Shortest Path found write result Relation
|
|
{
|
|
switch(spi->resultSelect)
|
|
{
|
|
case 0: // shortest path
|
|
{
|
|
int actEntryPos = visitedNodes->Find(actPQEntry->nodeNumber);
|
|
TreeEntry te = visitedNodes->GetTreeEntry(actEntryPos);
|
|
NodeEntry nE = te.GetNodeEntry();
|
|
delete actPQEntry;
|
|
actPQEntry = 0;
|
|
CcInt* startNodeInt = new CcInt(true,nE.beforeNodeId);
|
|
CcInt* endNodeInt = new CcInt(true,nE.nodeId);
|
|
attributes[0] = startNodeInt;
|
|
attributes[1] = endNodeInt;
|
|
CompositeKey actNodeKeyLower(attributes,kElems,false);
|
|
CompositeKey actNodeKeyUpper(attributes,kElems,true);
|
|
Tuple *newTuple = 0;
|
|
orelIt =
|
|
(OrderedRelationIterator*) orel->MakeRangeScan(actNodeKeyLower,
|
|
actNodeKeyUpper);
|
|
actTuple = orelIt->GetNextTuple();
|
|
found = false;
|
|
while (!found && actTuple != 0)
|
|
{
|
|
newTuple = new Tuple( rtt );
|
|
int i = 0;
|
|
while( i < actTuple->GetNoAttributes())
|
|
{
|
|
newTuple->CopyAttribute(i, actTuple,i);
|
|
i++;
|
|
}
|
|
CcInt* noOfNodes = new CcInt(true, 0);
|
|
spi->seqNoAttrIndex = i;
|
|
newTuple->PutAttribute(i,noOfNodes);
|
|
spi->resTuples->AppendTuple(newTuple);
|
|
if (newTuple != 0)
|
|
{
|
|
newTuple->DeleteIfAllowed();
|
|
newTuple = 0;
|
|
}
|
|
if (nE.GetBeforeNodeId() != startNode)
|
|
actEntryPos = visitedNodes->Find(nE.GetBeforeNodeId());
|
|
else
|
|
found = true;
|
|
if (!found)
|
|
{
|
|
te = visitedNodes->GetTreeEntry(actEntryPos);
|
|
nE = te.GetNodeEntry();
|
|
startNodeInt->DeleteIfAllowed();
|
|
endNodeInt->DeleteIfAllowed();
|
|
startNodeInt = new CcInt(true,nE.beforeNodeId);
|
|
endNodeInt = new CcInt(true,nE.nodeId);
|
|
attributes[0] = startNodeInt;
|
|
attributes[1] = endNodeInt;
|
|
CompositeKey actNodeKeyLower(attributes,kElems,false);
|
|
CompositeKey actNodeKeyUpper(attributes,kElems,true);
|
|
delete orelIt;
|
|
orelIt = (OrderedRelationIterator*)
|
|
orel->MakeRangeScan(actNodeKeyLower, actNodeKeyUpper);
|
|
if (actTuple != 0)
|
|
{
|
|
actTuple->DeleteIfAllowed();
|
|
actTuple = 0;
|
|
}
|
|
actTuple = orelIt->GetNextTuple();
|
|
}
|
|
}
|
|
if (startNodeInt != 0)
|
|
{
|
|
startNodeInt->DeleteIfAllowed();
|
|
startNodeInt = 0;
|
|
}
|
|
if (endNodeInt != 0)
|
|
{
|
|
endNodeInt->DeleteIfAllowed();
|
|
endNodeInt = 0;
|
|
}
|
|
if (actTuple != 0)
|
|
{
|
|
actTuple->DeleteIfAllowed();
|
|
actTuple = 0;
|
|
}
|
|
delete orelIt;
|
|
orelIt = 0;
|
|
break;
|
|
}
|
|
|
|
case 1: //Remaining elements in priority queue
|
|
{
|
|
PQEntryOrel* actElem;
|
|
for (int i = 0; i < prioQ->firstFree; i++)
|
|
{
|
|
actElem = prioQ->GetAndDeleteMin(visitedNodes);
|
|
if (actElem == 0) break;
|
|
CcInt* startNodeInt = new CcInt(true,actElem->beforeNodeNumber);
|
|
CcInt* endNodeInt = new CcInt(true,actElem->nodeNumber);
|
|
attributes[0] = startNodeInt;
|
|
attributes[1] = endNodeInt;
|
|
CompositeKey actNodeKeyLower(attributes,kElems,false);
|
|
CompositeKey actNodeKeyUpper(attributes,kElems,true);
|
|
orelIt =
|
|
(OrderedRelationIterator*) orel->MakeRangeScan(actNodeKeyLower,
|
|
actNodeKeyUpper);
|
|
actTuple = orelIt->GetNextTuple();
|
|
Tuple* newTuple = new Tuple( rtt );
|
|
int j = 0;
|
|
while( j < actTuple->GetNoAttributes())
|
|
{
|
|
newTuple->CopyAttribute(j, actTuple,j);
|
|
j++;
|
|
}
|
|
CcInt* noOfNodes = new CcInt(true, i+1);
|
|
newTuple->PutAttribute(j, noOfNodes);
|
|
spi->resTuples->AppendTuple(newTuple);
|
|
if (newTuple != 0)
|
|
{
|
|
newTuple->DeleteIfAllowed();
|
|
newTuple = 0;
|
|
}
|
|
if (startNodeInt != 0)
|
|
{
|
|
startNodeInt->DeleteIfAllowed();
|
|
startNodeInt = 0;
|
|
}
|
|
if (endNodeInt != 0)
|
|
{
|
|
endNodeInt->DeleteIfAllowed();
|
|
endNodeInt = 0;
|
|
}
|
|
if (actTuple != 0)
|
|
{
|
|
actTuple->DeleteIfAllowed();
|
|
actTuple = 0;
|
|
}
|
|
delete orelIt;
|
|
orelIt = 0;
|
|
if (actElem != 0)
|
|
{
|
|
delete actElem;
|
|
actElem = 0;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case 2: //visited sections
|
|
{
|
|
PQEntryOrel pqElem;
|
|
for (int i = 1; i < spTree->Size(); i++)
|
|
{
|
|
spTree->Get(i,pqElem);
|
|
CcInt* startNodeInt = new CcInt(true,pqElem.beforeNodeNumber);
|
|
CcInt* endNodeInt = new CcInt(true,pqElem.nodeNumber);
|
|
attributes[0] = startNodeInt;
|
|
attributes[1] = endNodeInt;
|
|
CompositeKey actNodeKeyLower(attributes,kElems,false);
|
|
CompositeKey actNodeKeyUpper(attributes,kElems,true);
|
|
orelIt =
|
|
(OrderedRelationIterator*) orel->MakeRangeScan(actNodeKeyLower,
|
|
actNodeKeyUpper);
|
|
actTuple = orelIt->GetNextTuple();
|
|
Tuple* newTuple = new Tuple( rtt );
|
|
int j = 0;
|
|
while( j < actTuple->GetNoAttributes())
|
|
{
|
|
newTuple->CopyAttribute(j, actTuple,j);
|
|
j++;
|
|
}
|
|
CcInt* noOfNodes = new CcInt(true, i);
|
|
newTuple->PutAttribute(j, noOfNodes);
|
|
spi->resTuples->AppendTuple(newTuple);
|
|
if (newTuple != 0)
|
|
{
|
|
newTuple->DeleteIfAllowed();
|
|
newTuple = 0;
|
|
}
|
|
if (startNodeInt != 0)
|
|
{
|
|
startNodeInt->DeleteIfAllowed();
|
|
startNodeInt = 0;
|
|
}
|
|
if (endNodeInt != 0)
|
|
{
|
|
endNodeInt->DeleteIfAllowed();
|
|
endNodeInt = 0;
|
|
}
|
|
if (actTuple != 0)
|
|
{
|
|
actTuple->DeleteIfAllowed();
|
|
actTuple = 0;
|
|
}
|
|
delete orelIt;
|
|
orelIt = 0;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case 3: //shortest path tree
|
|
{
|
|
NodeEntry actElem;
|
|
for (int i = 1; i < visitedNodes->fFree; i++)
|
|
{
|
|
actElem = visitedNodes->GetTreeEntry(i).GetNodeEntry();
|
|
CcInt* startNodeInt = new CcInt(true,actElem.GetBeforeNodeId());
|
|
CcInt* endNodeInt = new CcInt(true,actElem.GetNodeId());
|
|
attributes[0] = startNodeInt;
|
|
attributes[1] = endNodeInt;
|
|
CompositeKey actNodeKeyLower(attributes,kElems,false);
|
|
CompositeKey actNodeKeyUpper(attributes,kElems,true);
|
|
orelIt =
|
|
(OrderedRelationIterator*) orel->MakeRangeScan(actNodeKeyLower,
|
|
actNodeKeyUpper);
|
|
actTuple = orelIt->GetNextTuple();
|
|
Tuple* newTuple = new Tuple( rtt );
|
|
int j = 0;
|
|
while( j < actTuple->GetNoAttributes())
|
|
{
|
|
newTuple->CopyAttribute(j, actTuple,j);
|
|
j++;
|
|
}
|
|
CcInt* noOfNodes = new CcInt(true, i);
|
|
newTuple->PutAttribute(j, noOfNodes);
|
|
spi->resTuples->AppendTuple(newTuple);
|
|
|
|
if (newTuple != 0)
|
|
{
|
|
newTuple->DeleteIfAllowed();
|
|
newTuple = 0;
|
|
}
|
|
if (startNodeInt != 0)
|
|
{
|
|
startNodeInt->DeleteIfAllowed();
|
|
startNodeInt = 0;
|
|
}
|
|
if (endNodeInt != 0)
|
|
{
|
|
endNodeInt->DeleteIfAllowed();
|
|
endNodeInt = 0;
|
|
}
|
|
if (actTuple != 0)
|
|
{
|
|
actTuple->DeleteIfAllowed();
|
|
actTuple = 0;
|
|
}
|
|
delete orelIt;
|
|
orelIt = 0;
|
|
}
|
|
break;
|
|
}
|
|
|
|
default: //should never been reached;
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (actPQEntry != 0)
|
|
{
|
|
delete actPQEntry;
|
|
actPQEntry = 0;
|
|
}
|
|
if (actTuple != 0)
|
|
{
|
|
actTuple->DeleteIfAllowed();
|
|
actTuple = 0;
|
|
}
|
|
rtt->DeleteIfAllowed();
|
|
rtt = 0;
|
|
attributes.clear();
|
|
kElems.clear();
|
|
prioQ->Clear();
|
|
prioQ->Destroy();
|
|
delete prioQ;
|
|
visitedNodes->Destroy();
|
|
delete visitedNodes;
|
|
spTree->Destroy();
|
|
delete spTree;
|
|
spi->counter = spi->resTuples->GetNoTuples();
|
|
spi->iter = spi->resTuples->MakeScan();
|
|
return 0;
|
|
break;
|
|
}
|
|
|
|
case REQUEST:
|
|
{
|
|
if (spi != 0 && spi->resTuples != 0 && spi->iter != 0)
|
|
{
|
|
Tuple* res = spi->iter->GetNextTuple();
|
|
if (res != 0)
|
|
{
|
|
if (spi->resultSelect == 0)
|
|
{
|
|
res->PutAttribute( spi->seqNoAttrIndex,
|
|
new CcInt (true, spi->counter));
|
|
spi->counter--;
|
|
result.setAddr(res);
|
|
return YIELD;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
if (spi->resultSelect > 0 && spi->resultSelect < 4)
|
|
{
|
|
result.setAddr(res);
|
|
return YIELD;
|
|
break;
|
|
}
|
|
else
|
|
return CANCEL;
|
|
}
|
|
}
|
|
}
|
|
return CANCEL;
|
|
break;
|
|
}
|
|
|
|
case CLOSE:
|
|
{
|
|
if (spi != 0)
|
|
{
|
|
delete spi->iter;
|
|
spi->iter = 0;
|
|
delete spi->resTuples;
|
|
spi->resTuples = 0;
|
|
delete spi;
|
|
spi = 0;
|
|
local.setAddr(0);
|
|
}
|
|
return 0;
|
|
break;
|
|
}
|
|
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
const string OShortestPathASpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
|
"\"Example\" ) "
|
|
"( <text>(orel(tuple(a1:t1 ... an:tn))(ai1 ai2 ... ain)) x ti1 x ti2 x "
|
|
" int x (tuple->real) -> "
|
|
"(stream (tuple(a1:t1 ... an:tn SeqNo: int)))</text--->"
|
|
"<text>_ oshortestpatha [int,int, int;fun, fun]</text--->"
|
|
"<text>The operator uses a specialised ordered relation as graph"
|
|
" representation for shortest path computing. Each tuple represents an edge"
|
|
" of the graph consisting of at least two integer attributes identifying"
|
|
" the start node and the end node of the edge, and not less than two real"
|
|
" attributes representing the costs of the edge, and the distance function"
|
|
" to the target. The tuples may"
|
|
" contain further attributes giving additional cost informations or arbitrary"
|
|
" informations for each edge. The ordered relation should be ordered by the"
|
|
" numbers of the starting nodes at the first and by the number of the end "
|
|
" nodes at the second level to reduce the number of page accesses."
|
|
" The first two parameters select the start and the end node. The third "
|
|
" parameter selects the return value. In case of 0 the operator"
|
|
" returns the shortest path from node ti1 to ti2 as a stream of tuples"
|
|
" where each tuple is extended by a sequence number telling which is the"
|
|
" place of the tuple in the shortest path. In case of 1 the operator returns"
|
|
" the stream of tuples which are in the priority queue at the end of the"
|
|
" operation extended by their number in the queue. In case of 2 the operator"
|
|
" returns the stream of tuples which have been touched by the operator. In"
|
|
" case of 3 the operator returns a stream of tuples giving the shortest path"
|
|
" tree from the start node (up to the time the target node is reached)."
|
|
" The fourth and fifth parameter define two cost functions mapping the tuple"
|
|
" values to real numbers describing the costs of the edge, and the costs from"
|
|
" the end of the edge to the target node. Uses A Star Algorithm.</text--->"
|
|
"<text>query otest oshortestpatha[1,1,0;.Cost,.Weight] consume</text--->) )";
|
|
|
|
Operator oshortestpatha (
|
|
"oshortestpatha", // name
|
|
OShortestPathASpec, // specification
|
|
OShortestPathAValueMap, // value mapping
|
|
Operator::SimpleSelect, // trivial selection function
|
|
OShortestPathATypeMap // type mapping
|
|
);
|
|
|
|
|
|
/*
|
|
5. Type constructors
|
|
5.1 orel
|
|
|
|
*/
|
|
ListExpr ORelProperty() {
|
|
ListExpr examplelist = nl->TextAtom();
|
|
nl->AppendText(examplelist,"((\"Hagen\" 193)(\"Solingen\" 163))");
|
|
ListExpr listrep = nl->TextAtom();
|
|
nl->AppendText(listrep, "(<tuple>*) where <tuple> is "
|
|
"(<attr1> <attr2> <attr3> .."
|
|
". <attrn>)");
|
|
return nl->TwoElemList(
|
|
nl->FourElemList( nl->StringAtom("Signature"),
|
|
nl->StringAtom("ExampleTypeList"),
|
|
nl->StringAtom("List Rep"),
|
|
nl->StringAtom("Example List")),
|
|
nl->FourElemList( nl->StringAtom("TUPLE -> REL"),
|
|
nl->StringAtom("("+OREL+" (tuple "
|
|
"((city string)(pop int))) city)"),
|
|
listrep,
|
|
examplelist));
|
|
}
|
|
|
|
|
|
|
|
TypeConstructor cpporel( OREL, ORelProperty,
|
|
OrderedRelation::Out, OrderedRelation::In,
|
|
OrderedRelation::Out, OrderedRelation::In,
|
|
OrderedRelation::Create, OrderedRelation::Delete,
|
|
OrderedRelation::Open, OrderedRelation::Save,
|
|
OrderedRelation::Close, OrderedRelation::Clone,
|
|
OrderedRelation::Cast, OrderedRelation::SizeOf,
|
|
OrderedRelation::CheckKind);
|
|
|
|
|
|
/*
|
|
5.2 compkey
|
|
The implementation of CompositeKey is found in CompositeKey.h/cpp
|
|
|
|
*/
|
|
ListExpr CompKeyProperty() {
|
|
ListExpr examplelist = nl->TextAtom();
|
|
nl->AppendText(examplelist,"no listrepresentation");
|
|
ListExpr listrep = nl->TextAtom();
|
|
nl->AppendText(listrep, "no listrepresentation");
|
|
return nl->TwoElemList(
|
|
nl->FourElemList( nl->StringAtom("Signature"),
|
|
nl->StringAtom("ExampleTypeList"),
|
|
nl->StringAtom("List Rep"),
|
|
nl->StringAtom("Example List")),
|
|
nl->FourElemList( nl->StringAtom("-> DATA"),
|
|
nl->StringAtom("compkey"),
|
|
listrep,
|
|
examplelist));
|
|
}
|
|
|
|
|
|
|
|
TypeConstructor cppcompkey( "compkey", CompKeyProperty,
|
|
CompositeKey::Out, CompositeKey::In,
|
|
0, 0,
|
|
CompositeKey::Create, CompositeKey::Delete,
|
|
CompositeKey::Open, CompositeKey::Save,
|
|
CompositeKey::Close, CompositeKey::Clone,
|
|
CompositeKey::Cast, CompositeKey::SizeOf,
|
|
CompositeKey::CheckKind);
|
|
|
|
|
|
/*
|
|
12 Operator getotuples.
|
|
|
|
This operator takes a stream of tuple ids and looks for the specified
|
|
tuples in a usual relation given as the second argument. This relation
|
|
contains (may be among other) the key attributes of an ordered relation
|
|
that is given as the third attribute. From these attributes, an exactmatch
|
|
query on the ordered relation is executed and all results are put into
|
|
the output stream.
|
|
|
|
|
|
*/
|
|
ListExpr getotuples3TM(ListExpr args){
|
|
string err = "stream(tid) x rel x orel expected";
|
|
if(!nl->HasLength(args,3)){
|
|
return listutils::typeError(err + " (wrong number of args)");
|
|
}
|
|
if(!Stream<TupleIdentifier>::checkType(nl->First(args))){
|
|
return listutils::typeError(err + " (first arg is not a stream of tids)");
|
|
}
|
|
if(!Relation::checkType(nl->Second(args))){
|
|
return listutils::typeError(err + " (second arg is not a relation)");
|
|
}
|
|
if(!OrderedRelation::checkType(nl->Third(args))){
|
|
return listutils::typeError(err + " (third arg is not an ordered"
|
|
" relation)");
|
|
}
|
|
// get the List of key attributes of the ordered relation
|
|
ListExpr keyList = nl->Third(nl->Third(args));
|
|
// get the attribute list of the ordered relation
|
|
ListExpr oattrList = nl->Second(nl->Second(nl->Third(args)));
|
|
// get the attribute list of the auxilirary relation
|
|
ListExpr attrList = nl->Second(nl->Second(nl->Second(args)));
|
|
// init appendlist
|
|
ListExpr indexList = nl->TheEmptyList();
|
|
ListExpr last = nl->TheEmptyList();
|
|
bool first = true;
|
|
|
|
ListExpr rType;
|
|
ListExpr oType;
|
|
|
|
while(!nl->IsEmpty(keyList)){
|
|
string attrName = nl->SymbolValue(nl->First(keyList));
|
|
keyList = nl->Rest(keyList);
|
|
int index = listutils::findAttribute(attrList, attrName, rType);
|
|
if(!index){
|
|
return listutils::typeError("key attribute " + attrName +
|
|
" of the ordered relation "
|
|
"is not present in the auxiliarly relation");
|
|
}
|
|
if(!listutils::findAttribute(oattrList, attrName,oType)){
|
|
return listutils::typeError("internal error: wrong nested list"
|
|
" description detected");
|
|
}
|
|
if(!nl->Equal(rType,oType)){
|
|
return listutils::typeError("Types of attribute " + attrName
|
|
+ " differ");
|
|
}
|
|
if(first){
|
|
indexList = nl->OneElemList( nl->IntAtom(index-1));
|
|
last = indexList;
|
|
first = false;
|
|
} else {
|
|
last = nl->Append(last, nl->IntAtom(index-1));
|
|
}
|
|
}
|
|
return nl->ThreeElemList(
|
|
nl->SymbolAtom(Symbols::APPEND()),
|
|
indexList,
|
|
nl->TwoElemList(
|
|
listutils::basicSymbol<Stream<Tuple> >(),
|
|
nl->Second(nl->Third(args))));
|
|
}
|
|
|
|
|
|
class getotuples3Info{
|
|
public:
|
|
|
|
getotuples3Info(Word _stream, Relation* _auxRel,
|
|
OrderedRelation* _oRel, vector<int>& _keyIndexes):
|
|
stream(_stream), auxRel(_auxRel), oRel(_oRel), keyIndexes(_keyIndexes),
|
|
currentIter(0), keyTypes(_oRel->getKeyElemTypes()){
|
|
stream.open();
|
|
}
|
|
|
|
~getotuples3Info(){
|
|
stream.close();
|
|
if(currentIter){
|
|
delete currentIter;
|
|
}
|
|
}
|
|
|
|
Tuple* next(){
|
|
while(true){
|
|
if(currentIter){
|
|
Tuple* res = currentIter->GetNextTuple();
|
|
if(res){
|
|
return res;
|
|
} else {
|
|
delete currentIter;
|
|
currentIter = 0;
|
|
}
|
|
}
|
|
// no iterator available or no result from current iterator
|
|
|
|
Tuple* auxTuple =0;
|
|
do {
|
|
TupleIdentifier* tid = getNextTID();
|
|
if(!tid){ // input stream exhausted
|
|
return 0;
|
|
}
|
|
TupleId id = tid->GetTid();
|
|
tid->DeleteIfAllowed();
|
|
auxTuple = auxRel->GetTuple(id,true);
|
|
} while(auxTuple==0);
|
|
// now, we have an tuple from the auxiliary relation
|
|
|
|
// create a composite key from this tuple
|
|
vector<void*> attributes;
|
|
bool ok = true;
|
|
for(size_t i=0;i<keyIndexes.size();i++){
|
|
Attribute* attr = auxTuple->GetAttribute(keyIndexes[i]);
|
|
attributes.push_back(attr);
|
|
ok = ok && attr->IsDefined();
|
|
}
|
|
if(ok){ // forbid undefined values as keys
|
|
CompositeKey ckey(attributes, keyTypes);
|
|
CompositeKey ckey2(attributes, keyTypes,true);
|
|
currentIter = oRel->MakeRangeScan(ckey,ckey2);
|
|
}
|
|
auxTuple->DeleteIfAllowed();
|
|
}
|
|
}
|
|
private:
|
|
Stream<TupleIdentifier> stream;
|
|
Relation* auxRel;
|
|
OrderedRelation* oRel;
|
|
vector<int> keyIndexes; // in auxrel
|
|
GenericRelationIterator* currentIter;
|
|
vector<SmiKey::KeyDataType> keyTypes;
|
|
|
|
TupleIdentifier* getNextTID(){
|
|
TupleIdentifier* tid;
|
|
while((tid = stream.request())){
|
|
if(tid->IsDefined()){
|
|
return tid;
|
|
}
|
|
tid->DeleteIfAllowed();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
int getotuples3VM(Word* args, Word& result, int message,
|
|
Word& local, Supplier s) {
|
|
|
|
getotuples3Info* li = (getotuples3Info*) local.addr;
|
|
switch(message){
|
|
case OPEN: {
|
|
if(li){
|
|
delete li;
|
|
li = 0;
|
|
}
|
|
vector<int> v;
|
|
for(int i=3;i<qp->GetNoSons(s);i++){
|
|
v.push_back(((CcInt*)args[i].addr)->GetValue());
|
|
}
|
|
local.addr = new getotuples3Info(args[0],
|
|
(Relation*) args[1].addr,
|
|
(OrderedRelation*) args[2].addr,
|
|
v);
|
|
return 0;
|
|
}
|
|
case REQUEST: {
|
|
result.addr = li?li->next():0;
|
|
return result.addr?YIELD:CANCEL;
|
|
}
|
|
case CLOSE: {
|
|
if(li){
|
|
delete li;
|
|
local.addr = 0;
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
|
|
OperatorSpec getotuples3Spec(
|
|
"stream(tid) x rel(A) x orel(B) -> stream(B)",
|
|
"_ _ _ getotuples3",
|
|
"Retrieves tuples from an ordered relation with "
|
|
"help of an auxiliary relation. "
|
|
"The tuple ids from the stream are used to extract "
|
|
"tuples from the auxiliary relation containing the "
|
|
"key attributes of the ordered relation. "
|
|
"These key attributes are used again to extract tuples "
|
|
"from the ordered relation. ",
|
|
"query stree windowsintersectsS[box] transformstream "
|
|
"auxs ords getotuples3 consume"
|
|
);
|
|
|
|
Operator getotuples3Op(
|
|
"getotuples3",
|
|
getotuples3Spec.getStr(),
|
|
getotuples3VM,
|
|
Operator::SimpleSelect,
|
|
getotuples3TM
|
|
);
|
|
|
|
/*
|
|
13 Operator getotuples2
|
|
|
|
This operator works similat to getotuples3 but accepts
|
|
stream of tuples as the first argument. All attributes
|
|
of the incoming tuple stream, of the auximilary relation
|
|
and the ordered relation are put together. From the incoming
|
|
tuples, the tid attribute and from the auxiliary relation,
|
|
the key attributes are ommitted of course.
|
|
|
|
*/
|
|
ListExpr getotuples2TM(ListExpr args){
|
|
if(!nl->HasLength(args,3)){
|
|
return listutils::typeError("three arguments expected");
|
|
}
|
|
if(!Stream<Tuple>::checkType(nl->First(args))){
|
|
return listutils::typeError("first argument has to be a tuple stream");
|
|
}
|
|
if(!Relation::checkType(nl->Second(args))){
|
|
return listutils::typeError("the second argument must be a relation");
|
|
}
|
|
if(!OrderedRelation::checkType(nl->Third(args))){
|
|
return listutils::typeError("the third argument has to be an "
|
|
"ordered relation");
|
|
}
|
|
// check for TID attribute in the tuple stream and
|
|
// store the remaining attributes
|
|
ListExpr outAttr = nl->TheEmptyList();
|
|
ListExpr outAttrLast = nl->TheEmptyList();
|
|
bool first = true;
|
|
int tidIndex = 0;
|
|
int index = 0;
|
|
ListExpr inAttrList = nl->Second(nl->Second(nl->First(args)));
|
|
while(!nl->IsEmpty(inAttrList)){
|
|
ListExpr attr = nl->First(inAttrList);
|
|
inAttrList = nl->Rest(inAttrList);
|
|
index++;
|
|
if(TupleIdentifier::checkType(nl->Second(attr))){
|
|
if(tidIndex){
|
|
return listutils::typeError("incoming tuple stream contains "
|
|
"more than one tid attribute");
|
|
}
|
|
tidIndex = index;
|
|
} else {
|
|
if(first){
|
|
outAttr = nl->OneElemList(attr);
|
|
outAttrLast = outAttr;
|
|
first = false;
|
|
} else {
|
|
outAttrLast = nl->Append(outAttrLast, attr);
|
|
}
|
|
}
|
|
}
|
|
|
|
map<string, ListExpr> keyAttributes; // key -> Type
|
|
|
|
ListExpr orelAttrList = nl->Second(nl->Second(nl->Third(args)));
|
|
ListExpr keys = nl->Third(nl->Third(args));
|
|
|
|
vector<int> keyIndexes1; // where to find indexes in orel
|
|
|
|
while(!nl->IsEmpty(keys)){
|
|
string keyName = nl->SymbolValue(nl->First(keys));
|
|
keys = nl->Rest(keys);
|
|
ListExpr type;
|
|
index = listutils::findAttribute(orelAttrList, keyName, type);
|
|
keyAttributes[keyName] = type;
|
|
keyIndexes1.push_back(index);
|
|
}
|
|
|
|
index = 0;
|
|
vector<int> keyIndexes2; // where to find key attributes in aux relation
|
|
ListExpr auxRelAttrList = nl->Second(nl->Second(nl->Second(args)));
|
|
while(!nl->IsEmpty(auxRelAttrList)){
|
|
index++;
|
|
ListExpr attr = nl->First(auxRelAttrList);
|
|
auxRelAttrList = nl->Rest(auxRelAttrList);
|
|
string name = nl->SymbolValue(nl->First(attr));
|
|
if(keyAttributes.find(name) != keyAttributes.end()){
|
|
// found a key attribute
|
|
if(!nl->Equal(keyAttributes[name], nl->Second(attr))){
|
|
return listutils::typeError("key attribute types of auxiliary "
|
|
"relation and ordered relation differ");
|
|
}
|
|
keyIndexes2.push_back(index);
|
|
} else { // found additionally attribute
|
|
if(first){
|
|
outAttr = nl->OneElemList(attr);
|
|
outAttrLast = outAttr;
|
|
first = false;
|
|
} else {
|
|
outAttrLast = nl->Append(outAttrLast, attr);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(keyIndexes2.size() != keyIndexes1.size()){
|
|
return listutils::typeError("auxiliary relation does not contain all "
|
|
"key attributes of the ordered relation. ");
|
|
}
|
|
|
|
while(!nl->IsEmpty(orelAttrList)){
|
|
ListExpr attr = nl->First(orelAttrList);
|
|
orelAttrList = nl->Rest(orelAttrList);
|
|
if(first){
|
|
outAttr = nl->OneElemList(attr);
|
|
outAttrLast = outAttr;
|
|
first = false;
|
|
} else {
|
|
outAttrLast = nl->Append(outAttrLast, attr);
|
|
}
|
|
}
|
|
|
|
// the append list consists of the postion of the tid attribute,
|
|
// the positions of the key attributes in the auxiliary relation
|
|
// and the positions of the key attributes in the ordered relation
|
|
|
|
ListExpr appendList = nl->OneElemList(nl->IntAtom(tidIndex-1));
|
|
ListExpr appendLast = appendList;
|
|
for(size_t i=0;i<keyIndexes2.size(); i++){
|
|
appendLast = nl->Append(appendLast, nl->IntAtom(keyIndexes2[i]-1));
|
|
}
|
|
for(size_t i=0;i<keyIndexes1.size(); i++){
|
|
appendLast = nl->Append(appendLast, nl->IntAtom(keyIndexes1[i]-1));
|
|
}
|
|
return nl->ThreeElemList(
|
|
nl->SymbolAtom(Symbols::APPEND()),
|
|
appendList,
|
|
nl->TwoElemList(
|
|
listutils::basicSymbol<Stream<Tuple> >(),
|
|
nl->TwoElemList(
|
|
listutils::basicSymbol<Tuple>(),
|
|
outAttr)));
|
|
}
|
|
|
|
|
|
/*
|
|
Class ~getotuples2Info~
|
|
|
|
*/
|
|
|
|
class getotuples2Info{
|
|
public:
|
|
getotuples2Info( Word _stream,
|
|
Relation* _rel,
|
|
OrderedRelation* _orel,
|
|
int _tidPos, // position of tid attribute in input
|
|
vector<int>& _keyAttributesAux,
|
|
vector<int>& _keyAttributesOrdered,
|
|
ListExpr resultType):
|
|
stream(_stream), rel(_rel), orel(_orel), tidPos(_tidPos),
|
|
keyAttributesAux(_keyAttributesAux),
|
|
keyAttributesOrdered(_keyAttributesOrdered),
|
|
keyTypes(_orel->getKeyElemTypes()) {
|
|
tt = new TupleType(resultType);
|
|
stream.open();
|
|
it = 0;
|
|
currentInTuple = 0;
|
|
currentAuxTuple = 0;
|
|
useRel = 0;
|
|
useStream = 0;
|
|
}
|
|
|
|
~getotuples2Info(){
|
|
tt->DeleteIfAllowed();
|
|
stream.close();
|
|
if(currentInTuple){
|
|
currentInTuple->DeleteIfAllowed();
|
|
}
|
|
if(currentAuxTuple){
|
|
currentAuxTuple->DeleteIfAllowed();
|
|
}
|
|
if(it){
|
|
delete it;
|
|
}
|
|
if(useStream){
|
|
delete useStream;
|
|
}
|
|
if(useRel){
|
|
delete useRel;
|
|
}
|
|
}
|
|
|
|
Tuple* next(){
|
|
while(true){
|
|
if(it){
|
|
Tuple* oTuple = it->GetNextTuple();
|
|
if(oTuple){
|
|
Tuple* res = createResTuple(oTuple);
|
|
oTuple->DeleteIfAllowed();
|
|
return res;
|
|
} else {
|
|
deleteIter();
|
|
}
|
|
}
|
|
getNextIter();
|
|
if(!it){
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
private:
|
|
Stream<Tuple> stream;
|
|
Relation* rel;
|
|
OrderedRelation *orel;
|
|
int tidPos;
|
|
vector<int> keyAttributesAux;
|
|
vector<int> keyAttributesOrdered;
|
|
vector<SmiKey::KeyDataType> keyTypes;
|
|
TupleType* tt;
|
|
vector<bool>* useStream;
|
|
vector<bool>* useRel;
|
|
|
|
Tuple* currentInTuple;
|
|
Tuple* currentAuxTuple;
|
|
|
|
GenericRelationIterator* it;
|
|
|
|
|
|
|
|
/*
|
|
~deleteIter~
|
|
|
|
Deletes currentInTuple, currentAuxTuple, and it.
|
|
|
|
*/
|
|
void deleteIter(){
|
|
assert(it);
|
|
assert(currentInTuple);
|
|
assert(currentAuxTuple);
|
|
currentInTuple->DeleteIfAllowed();
|
|
currentInTuple = 0;
|
|
currentAuxTuple->DeleteIfAllowed();
|
|
currentAuxTuple = 0;
|
|
delete it;
|
|
it = 0;
|
|
}
|
|
|
|
/*
|
|
~createResTuple~
|
|
|
|
Creates the result tuple from currentInTuple, currentAuxTuple,
|
|
and oTuple.
|
|
|
|
*/
|
|
Tuple* createResTuple(Tuple* oTuple){
|
|
createUseStream();
|
|
createUseRel();
|
|
Tuple* result = new Tuple(tt);
|
|
int targetPos = 0;
|
|
// copy non tid attributes of in tuple
|
|
for(int i=0;i<currentInTuple->GetNoAttributes();i++){
|
|
if(useStream->at(i)){
|
|
result->CopyAttribute(i, currentInTuple, targetPos);
|
|
targetPos++;
|
|
}
|
|
}
|
|
// copy non key attributes of aux relation
|
|
for(int i=0;i<currentAuxTuple->GetNoAttributes();i++){
|
|
if(useRel->at(i)){
|
|
result->CopyAttribute(i, currentAuxTuple, targetPos);
|
|
targetPos++;
|
|
}
|
|
}
|
|
// finally copy all attributes from ordered tuple into target
|
|
for(int i=0;i<oTuple->GetNoAttributes(); i++){
|
|
result->CopyAttribute(i, oTuple, targetPos);
|
|
targetPos++;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
/*
|
|
~createUseStream~
|
|
|
|
Creates a bit vector stating whether an attribute of
|
|
the incoming stream should be part of the result.
|
|
|
|
*/
|
|
void createUseStream(){
|
|
if(useStream) {
|
|
return;
|
|
}
|
|
assert(currentInTuple);
|
|
useStream = new vector<bool>();
|
|
|
|
for(int i=0;i<currentInTuple->GetNoAttributes(); i++){
|
|
useStream->push_back(true);
|
|
}
|
|
useStream->at(tidPos) = false;
|
|
}
|
|
|
|
/*
|
|
~createUseRel~
|
|
|
|
Creates a bit vector stating whether an attribute of
|
|
the auxiliary relation should be part of the result.
|
|
|
|
*/
|
|
void createUseRel(){
|
|
if(useRel){
|
|
return;
|
|
}
|
|
assert(currentAuxTuple);
|
|
useRel = new vector<bool>();
|
|
for(int i=0;i<currentAuxTuple->GetNoAttributes();i++){
|
|
useRel->push_back(true);
|
|
}
|
|
for(size_t i=0;i<keyAttributesAux.size();i++){
|
|
useRel->at(keyAttributesAux[i]) = false;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
Creates currentInTuple, currentAuxTuple and it.
|
|
|
|
*/
|
|
void getNextIter(){
|
|
while(true){
|
|
getNextStreamTuple();
|
|
if(!currentInTuple){ // stream exhausted
|
|
return;
|
|
}
|
|
getNextAuxTuple();
|
|
if(currentAuxTuple){
|
|
createIter();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
~getNextStreamTuple~
|
|
|
|
scans the incoming stream until a tuple containing a
|
|
defined tid is found. This tuple is stored as
|
|
currentInTuple.
|
|
|
|
*/
|
|
void getNextStreamTuple(){
|
|
if(currentInTuple){
|
|
currentInTuple->DeleteIfAllowed();
|
|
currentInTuple = 0;
|
|
}
|
|
Tuple* t;
|
|
while((t=stream.request())){
|
|
Attribute* tid = t->GetAttribute(tidPos);
|
|
if(tid->IsDefined()){
|
|
currentInTuple = t;
|
|
return;
|
|
} else {
|
|
t->DeleteIfAllowed();
|
|
t = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
~getNextAuxTuple~
|
|
|
|
Retrieves a tuple from the auxiliary relation
|
|
using the tuple id from currentInTuple.
|
|
|
|
*/
|
|
void getNextAuxTuple(){
|
|
assert(currentInTuple);
|
|
TupleIdentifier* tid = (TupleIdentifier*)
|
|
currentInTuple->GetAttribute(tidPos);
|
|
TupleId id = tid->GetTid();
|
|
currentAuxTuple = rel->GetTuple(id, true);
|
|
}
|
|
|
|
|
|
/*
|
|
~createIter~
|
|
|
|
Creates an iterator over the ordered relation using the
|
|
keyy attributes from currentAuxTuple.
|
|
|
|
*/
|
|
void createIter(){
|
|
if(it){
|
|
delete it;
|
|
it = 0;
|
|
}
|
|
vector<void*> attributes;
|
|
bool ok = true;
|
|
for(size_t i=0;i<keyAttributesAux.size();i++){
|
|
Attribute* attr = currentAuxTuple->GetAttribute(keyAttributesAux[i]);
|
|
attributes.push_back(attr);
|
|
ok = ok && attr->IsDefined();
|
|
}
|
|
if(ok){ // forbid undefined values as keys
|
|
CompositeKey ckey(attributes, keyTypes);
|
|
CompositeKey ckey2(attributes, keyTypes,true);
|
|
it = orel->MakeRangeScan(ckey,ckey2);
|
|
}
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
int getotuples2VM(Word* args, Word& result, int message,
|
|
Word& local, Supplier s) {
|
|
|
|
getotuples2Info* li = (getotuples2Info*) local.addr;
|
|
switch(message){
|
|
case OPEN:{
|
|
if(li){
|
|
delete li;
|
|
local.addr = 0;
|
|
}
|
|
Relation* rel = (Relation*) args[1].addr;
|
|
OrderedRelation* orel = (OrderedRelation*) args[2].addr;
|
|
int tidPos = ((CcInt*) args[3].addr)->GetValue();
|
|
vector<int> auxKeyPos;
|
|
vector<int> oKeyPos;
|
|
int keys = (qp->GetNoSons(s) - 4) / 2;
|
|
for(int i=4; i<4+keys;i++){
|
|
auxKeyPos.push_back(((CcInt*) args[i].addr)->GetValue());
|
|
}
|
|
for(int i=4+keys; i<qp->GetNoSons(s);i++){
|
|
oKeyPos.push_back(((CcInt*) args[i].addr)->GetValue());
|
|
}
|
|
assert(auxKeyPos.size() == oKeyPos.size());
|
|
ListExpr tt = nl->Second(GetTupleResultType(s));
|
|
local.addr = new getotuples2Info( args[0], rel, orel, tidPos,
|
|
auxKeyPos, oKeyPos,tt);
|
|
return 0;
|
|
}
|
|
case REQUEST:
|
|
result.addr = li?li->next():0;
|
|
return result.addr?YIELD:CANCEL;
|
|
case CLOSE:
|
|
if(li){
|
|
delete li;
|
|
local.addr = 0;
|
|
}
|
|
return 0;
|
|
}
|
|
return -321;
|
|
}
|
|
|
|
|
|
OperatorSpec getotuples2Spec(
|
|
" stream(tuple(X)) x rel(tuple(Y)) x orel(tuple(Z),K) "
|
|
" -> stream(tuple(X \\ {TID} @ Y \\ K @ Z)) ",
|
|
"_ _ _ getotuples2 ",
|
|
"Extract tuples from an ordered relation with help of an "
|
|
"auxiliary relation. All attributes of the tuples "
|
|
"are put together in the output tuple. ",
|
|
"query stree windowsintersectsS[box] extend[Bla : 123] "
|
|
"auxs ords getotuples2 consume"
|
|
);
|
|
|
|
Operator getotuples2Op(
|
|
"getotuples2",
|
|
getotuples2Spec.getStr(),
|
|
getotuples2VM,
|
|
Operator::SimpleSelect,
|
|
getotuples2TM
|
|
);
|
|
|
|
|
|
|
|
/*
|
|
13 getotuples
|
|
|
|
This operator gets a stream of tuples containing the key
|
|
attributes of an ordered relation and retrieves the corresponding
|
|
tuples from the ordered relation.
|
|
|
|
*/
|
|
|
|
ListExpr getotuplesTM(ListExpr args){
|
|
string err = "stream(tuple) x orel expected";
|
|
if(!nl->HasLength(args,2)){
|
|
return listutils::typeError(err + " (wrong number of args)");
|
|
}
|
|
if( !Stream<Tuple>::checkType(nl->First(args))
|
|
|| !OrderedRelation::checkType(nl->Second(args))){
|
|
return listutils::typeError(err);
|
|
}
|
|
ListExpr appendList=nl->TheEmptyList();
|
|
ListExpr last=nl->TheEmptyList();
|
|
ListExpr stype;
|
|
ListExpr rtype;
|
|
ListExpr keyList = nl->Third(nl->Second(args));
|
|
ListExpr oattrList = nl->Second(nl->Second(nl->Second(args)));
|
|
ListExpr attrList = nl->Second(nl->Second(nl->First(args)));
|
|
bool first = true;
|
|
|
|
|
|
|
|
|
|
while(!nl->IsEmpty(keyList)){
|
|
string name = nl->SymbolValue(nl->First(keyList));
|
|
keyList = nl->Rest(keyList);
|
|
int index = listutils::findAttribute(attrList, name, stype );
|
|
if(!index){
|
|
return listutils::typeError("key attribute " + name +
|
|
" not part of the tuple stream");
|
|
}
|
|
if(!listutils::findAttribute(oattrList,name,rtype)){
|
|
return listutils::typeError("Internal error: keyname in "
|
|
"orel not found");
|
|
}
|
|
if(!nl->Equal(stype,rtype)){
|
|
return listutils::typeError("type of attribute " + name + " differ");
|
|
}
|
|
if(first){
|
|
appendList = nl->OneElemList(nl->IntAtom(index-1));
|
|
last = appendList;
|
|
first = false;
|
|
} else {
|
|
last = nl->Append(last, nl->IntAtom(index-1));
|
|
}
|
|
}
|
|
return nl->ThreeElemList(
|
|
nl->SymbolAtom(Symbols::APPEND()),
|
|
appendList,
|
|
nl->TwoElemList(
|
|
listutils::basicSymbol<Stream<Tuple> >(),
|
|
nl->Second(nl->Second(args))));
|
|
}
|
|
|
|
|
|
class getotuplesInfo{
|
|
public:
|
|
|
|
getotuplesInfo(Word _stream, OrderedRelation* _oRel,
|
|
vector<int>& _keyIndexes):
|
|
stream(_stream), oRel(_oRel), keyIndexes(_keyIndexes),
|
|
currentIter(0), keyTypes(_oRel->getKeyElemTypes()){
|
|
stream.open();
|
|
}
|
|
|
|
~getotuplesInfo(){
|
|
stream.close();
|
|
if(currentIter){
|
|
delete currentIter;
|
|
}
|
|
}
|
|
|
|
Tuple* next(){
|
|
while(true){
|
|
if(currentIter){
|
|
Tuple* res = currentIter->GetNextTuple();
|
|
if(res){
|
|
return res;
|
|
} else {
|
|
delete currentIter;
|
|
currentIter = 0;
|
|
}
|
|
}
|
|
// no iterator available or no result from current iterator
|
|
|
|
|
|
Tuple* inTuple = stream.request();
|
|
if(!inTuple){
|
|
return 0;
|
|
}
|
|
|
|
// create a composite key from this tuple
|
|
vector<void*> attributes;
|
|
bool ok = true;
|
|
for(size_t i=0;i<keyIndexes.size() && ok;i++){
|
|
Attribute* attr = inTuple->GetAttribute(keyIndexes[i]);
|
|
attributes.push_back(attr);
|
|
ok = ok && attr->IsDefined();
|
|
}
|
|
if(ok){ // forbid undefined values as keys
|
|
CompositeKey ckey(attributes, keyTypes);
|
|
CompositeKey ckey2(attributes, keyTypes,true);
|
|
currentIter = oRel->MakeRangeScan(ckey,ckey2);
|
|
}
|
|
inTuple->DeleteIfAllowed();
|
|
}
|
|
}
|
|
|
|
|
|
private:
|
|
Stream<Tuple> stream;
|
|
OrderedRelation* oRel;
|
|
vector<int> keyIndexes; // in tuple stream
|
|
GenericRelationIterator* currentIter;
|
|
vector<SmiKey::KeyDataType> keyTypes;
|
|
};
|
|
|
|
|
|
|
|
int getotuplesVM(Word* args, Word& result, int message,
|
|
Word& local, Supplier s) {
|
|
|
|
getotuplesInfo* li = (getotuplesInfo*) local.addr;
|
|
switch(message){
|
|
case OPEN: {
|
|
if(li){
|
|
delete li;
|
|
li = 0;
|
|
}
|
|
vector<int> v;
|
|
for(int i=2;i<qp->GetNoSons(s);i++){
|
|
int index = ((CcInt*)(args[i].addr))->GetValue();
|
|
v.push_back(index);
|
|
}
|
|
local.addr = new getotuplesInfo(args[0],
|
|
(OrderedRelation*) args[1].addr,
|
|
v);
|
|
return 0;
|
|
}
|
|
case REQUEST: {
|
|
result.addr = li?li->next():0;
|
|
return result.addr?YIELD:CANCEL;
|
|
}
|
|
case CLOSE: {
|
|
if(li){
|
|
delete li;
|
|
local.addr = 0;
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
|
|
OperatorSpec getotuplesSpec(
|
|
"stream(tuple) x orel(B) -> stream(B)",
|
|
"_ _ getotuples",
|
|
"Retrieves tuples from an ordered relation with "
|
|
"help of a tuples stream containing the key attributes "
|
|
" of the ordered relation.",
|
|
"query stree windowsintersects[box] ords getotuples consume"
|
|
);
|
|
|
|
Operator getotuplesOp(
|
|
"getotuples",
|
|
getotuplesSpec.getStr(),
|
|
getotuplesVM,
|
|
Operator::SimpleSelect,
|
|
getotuplesTM
|
|
);
|
|
|
|
|
|
|
|
/*
|
|
6. OrderedRelationAlgebra definition
|
|
|
|
*/
|
|
class OrderedRelationAlgebra : public Algebra {
|
|
public:
|
|
OrderedRelationAlgebra() : Algebra() {
|
|
AddTypeConstructor(&cpporel);
|
|
cpporel.AssociateKind(Kind::REL());
|
|
|
|
AddTypeConstructor(&cppcompkey);
|
|
cppcompkey.AssociateKind(Kind::DATA());
|
|
|
|
AddOperator(&oleftrange);
|
|
AddOperator(&orightrange);
|
|
AddOperator(&orange);
|
|
AddOperator(&oshortestpathd);
|
|
AddOperator(&oshortestpatha);
|
|
|
|
AddOperator(&getotuples2Op);
|
|
AddOperator(&getotuplesOp);
|
|
|
|
#ifdef USE_PROGRESS
|
|
oleftrange.EnableProgress();
|
|
orightrange.EnableProgress();
|
|
orange.EnableProgress();
|
|
#endif
|
|
};
|
|
|
|
~OrderedRelationAlgebra() {};
|
|
};
|
|
|
|
|
|
/*
|
|
7. Registration of the OrderedRelationAlgebra
|
|
|
|
*/
|
|
extern "C" Algebra* InitializeOrderedRelationAlgebra(NestedList* nlRef,
|
|
QueryProcessor* qpRef) {
|
|
nl = nlRef;
|
|
qp = qpRef;
|
|
am = SecondoSystem::GetAlgebraManager();
|
|
return new OrderedRelationAlgebra();
|
|
}
|
|
|
|
|