22596 lines
616 KiB
C++
22596 lines
616 KiB
C++
/*
|
|
|
|
----
|
|
This file is part of SECONDO.
|
|
|
|
Copyright (C) 2016,
|
|
University in Hagen,
|
|
Faculty of Mathematics and Computer Science,
|
|
Database Systems for New Applications.
|
|
|
|
SECONDO is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
SECONDO is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with SECONDO; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
----
|
|
|
|
|
|
//[_] [\_]
|
|
|
|
*/
|
|
|
|
#include "MemCatalog.h"
|
|
#include "Algebra.h"
|
|
#include "NestedList.h"
|
|
#include "QueryProcessor.h"
|
|
#include "ListUtils.h"
|
|
#include "Attribute.h"
|
|
#include "AlgebraManager.h"
|
|
#include "Operator.h"
|
|
#include "StandardTypes.h"
|
|
#include "NList.h"
|
|
#include "Symbols.h"
|
|
#include "SecondoCatalog.h"
|
|
#include "SecondoSystem.h"
|
|
#include "Algebras/Relation-C++/RelationAlgebra.h"
|
|
#include "Algebras/OrderedRelation/OrderedRelationAlgebra.h"
|
|
//#include "GraphAlgebra.h"
|
|
#include "Stream.h"
|
|
#include "MMRTree.h"
|
|
#include "MMMTree.h"
|
|
#include "Algebras/FText/FTextAlgebra.h"
|
|
//#include "MovingRegionAlgebra.h"
|
|
#include "Algebras/Rectangle/RectangleAlgebra.h"
|
|
#include "Algebras/Spatial/Point.h"
|
|
#include "Algebras/Spatial/SpatialAlgebra.h"
|
|
#include "Algebras/Temporal/TemporalAlgebra.h"
|
|
#include "AvlTree.h"
|
|
#include "StopWatch.h"
|
|
|
|
#include "MainMemoryExt.h"
|
|
#include "ttree.h"
|
|
|
|
#include "MPointer.h"
|
|
// #include "mapmatch.h"
|
|
|
|
|
|
#include <ctime>
|
|
#include <exception>
|
|
#include <string>
|
|
#include <map>
|
|
#include <vector>
|
|
#include <limits>
|
|
#include <algorithm>
|
|
|
|
#include <ctime>
|
|
|
|
|
|
#include "MemoryVectorObject.h"
|
|
#include "MemoryPQueue.h"
|
|
#include "MemoryStack.h"
|
|
|
|
#include "MGraph2.h"
|
|
#include "MGraph3.h"
|
|
#include "Algebras/Standard-C++/LongInt.h"
|
|
|
|
#include <chrono>
|
|
#include <unordered_map>
|
|
|
|
|
|
using namespace std;
|
|
|
|
extern NestedList* nl;
|
|
extern QueryProcessor *qp;
|
|
|
|
|
|
ostream& operator<<(ostream& o, const mm2algebra::AttrIdPair& t) {
|
|
o << "(";
|
|
t.getAttr()->Print(o);
|
|
o << ", " << t.getTid() << ")";
|
|
return o;
|
|
}
|
|
|
|
|
|
namespace mm2algebra {
|
|
|
|
MemCatalog* catalog = 0;
|
|
|
|
MemCatalog* getMemCatalog(){
|
|
return catalog;
|
|
}
|
|
|
|
|
|
|
|
#define MEMORYMTREEOBJECT "memoryMTreeObject"
|
|
|
|
|
|
|
|
bool checkUsesArgs(ListExpr args){
|
|
ListExpr tmp = args;
|
|
while(!nl->IsEmpty(tmp)){
|
|
if(!nl->HasLength(nl->First(args),2)){
|
|
return false;
|
|
}
|
|
tmp = nl->Rest(tmp);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
bool getMemSubType(ListExpr type, ListExpr& res){
|
|
if(MPointer::checkType(type)){
|
|
res = nl->Second(nl->Second(type));
|
|
return true;
|
|
}
|
|
if(!Mem::checkType(type)){
|
|
return false;
|
|
}
|
|
res = nl->Second(type);
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
|
|
4 Auxiliary functions
|
|
|
|
*/
|
|
namespace rtreehelper{
|
|
|
|
|
|
int getDimension(ListExpr type){
|
|
if(listutils::isKind(type,Kind::SPATIAL2D())) return 2;
|
|
if(listutils::isKind(type,Kind::SPATIAL3D())) return 3;
|
|
if(listutils::isKind(type,Kind::SPATIAL4D())) return 4;
|
|
if(listutils::isKind(type,Kind::SPATIAL8D())) return 8;
|
|
return -1;
|
|
}
|
|
|
|
string BasicType(){
|
|
return "rtree";
|
|
}
|
|
|
|
bool checkType(ListExpr type){
|
|
if(!nl->HasLength(type,2)){
|
|
return false;
|
|
}
|
|
if(!listutils::isSymbol(nl->First(type),BasicType())){
|
|
return false;
|
|
}
|
|
if(nl->AtomType(nl->Second(type))!=IntType){
|
|
return false;
|
|
}
|
|
int dim = nl->IntValue(nl->Second(type));
|
|
return (dim==2) || (dim==3) || (dim==4) || (dim==8);
|
|
}
|
|
|
|
bool checkType(ListExpr type, int dim){
|
|
if(!checkType(type)){
|
|
return false;
|
|
}
|
|
return nl->IntValue(nl->Second(type))==dim;
|
|
}
|
|
|
|
ListExpr getType(int dim){
|
|
return nl->TwoElemList( nl->SymbolAtom(BasicType()),
|
|
nl->IntAtom(dim));
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
namespace mtreehelper{
|
|
|
|
double distance(const Point* p1, const Point* p2, Geoid* geoid) {
|
|
if(!p1->IsDefined() && !p2->IsDefined()){
|
|
return 0;
|
|
}
|
|
if(!p1->IsDefined() || !p2->IsDefined()){
|
|
return std::numeric_limits<double>::max();
|
|
}
|
|
return p1->Distance(*p2, geoid);
|
|
}
|
|
|
|
double distance(const CcString* s1, const CcString* s2, Geoid* geoid) {
|
|
if(!s1->IsDefined() && !s2->IsDefined()){
|
|
return 0;
|
|
}
|
|
if(!s1->IsDefined() || !s2->IsDefined()){
|
|
return std::numeric_limits<double>::max();
|
|
}
|
|
return stringutils::ld(s1->GetValue() ,s2->GetValue());
|
|
}
|
|
|
|
double distance(const CcInt* i1, const CcInt* i2, Geoid* geoid) {
|
|
if(!i1->IsDefined() && !i2->IsDefined()){
|
|
return 0;
|
|
}
|
|
if(!i1->IsDefined() || !i2->IsDefined()){
|
|
return std::numeric_limits<double>::max();
|
|
}
|
|
return abs(i1->GetValue() - i2->GetValue());
|
|
}
|
|
|
|
double distance(const CcReal* r1, const CcReal* r2, Geoid* geoid) {
|
|
if(!r1->IsDefined() && !r2->IsDefined()){
|
|
return 0;
|
|
}
|
|
if(!r1->IsDefined() || !r2->IsDefined()){
|
|
return std::numeric_limits<double>::max();
|
|
}
|
|
return abs(r1->GetValue() - r2->GetValue());
|
|
}
|
|
|
|
template<unsigned int dim>
|
|
double distance(const Rectangle<dim>* r1,
|
|
const Rectangle<dim>* r2, Geoid* geoid) {
|
|
if(!r1->IsDefined() && !r2->IsDefined()){
|
|
return 0;
|
|
}
|
|
if(!r1->IsDefined() || !r2->IsDefined()){
|
|
return std::numeric_limits<double>::max();
|
|
}
|
|
return r1->Distance(*r2);
|
|
}
|
|
|
|
double distance(const temporalalgebra::MPoint* mp1,
|
|
const temporalalgebra::MPoint* mp2, Geoid* geoid) {
|
|
if (!mp1->IsDefined() && !mp2->IsDefined()) {
|
|
return 0;
|
|
}
|
|
if (!mp1->IsDefined() || !mp2->IsDefined()) {
|
|
return std::numeric_limits<double>::max();
|
|
}
|
|
datetime::DateTime duration(0, 3600000, datetime::durationtype);
|
|
return temporalalgebra::DistanceComputation<temporalalgebra::MPoint,
|
|
temporalalgebra::UPoint>::DistanceAvg(*mp1, *mp2, duration, true, geoid);
|
|
}
|
|
|
|
double distance(const temporalalgebra::CUPoint* cup1,
|
|
const temporalalgebra::CUPoint* cup2, Geoid* geoid) {
|
|
if (!cup1->IsDefined() && !cup2->IsDefined()) {
|
|
return 0;
|
|
}
|
|
if (!cup1->IsDefined() || !cup2->IsDefined()) {
|
|
return std::numeric_limits<double>::max();
|
|
}
|
|
datetime::DateTime duration(0, 3600000, datetime::durationtype);
|
|
return cup1->DistanceAvg(*cup2, duration, true, geoid); // upper bound dist
|
|
}
|
|
|
|
double distance(const temporalalgebra::CMPoint* cmp1,
|
|
const temporalalgebra::CMPoint* cmp2, Geoid* geoid) {
|
|
if (!cmp1->IsDefined() && !cmp2->IsDefined()) {
|
|
return 0;
|
|
}
|
|
if (!cmp1->IsDefined() || !cmp2->IsDefined()) {
|
|
return std::numeric_limits<double>::max();
|
|
}
|
|
datetime::DateTime duration(0, 3600000, datetime::durationtype);
|
|
return temporalalgebra::DistanceComputation<temporalalgebra::CMPoint,
|
|
temporalalgebra::CUPoint>::DistanceAvg(
|
|
*cmp1, *cmp2, duration, true, geoid);
|
|
}
|
|
|
|
template<class T>
|
|
double distance(const T* o1, const T* o2, double alpha, Geoid* geoid) {
|
|
// cout << " CALL dist for " << o1->first << " and " << o2->first << endl;
|
|
// auto t1 = chrono::high_resolution_clock::now();
|
|
// double spaDist = o1->first.DistanceAvg(o2->first, geoid);
|
|
double spaDist = distance(&(o1->first), &(o2->first), geoid);
|
|
// auto t2 = chrono::high_resolution_clock::now();
|
|
// auto duration =
|
|
// chrono::duration_cast<chrono::microseconds>(t2 - t1).count();
|
|
// cout << " spatial distance: " << spaDist << " after "
|
|
// << (double)duration / 1000.0 << " ms" << endl;
|
|
// cout << " num of spatial units: (" << o1->first.GetNoComponents()
|
|
// << ", " << o2->first.GetNoComponents()
|
|
// << "), num of symbolic units: ("
|
|
// << o2->second.GetNoComponents() << ", "
|
|
// << o2->second.GetNoComponents() << ")" << endl;
|
|
set<string> allLabels1, allLabels2;
|
|
o1->second.InsertLabels(allLabels1);
|
|
o2->second.InsertLabels(allLabels2);
|
|
double symDist = 1.0 - stj::jaccardSimilarity(allLabels1, allLabels2);
|
|
// auto t3 = chrono::high_resolution_clock::now();
|
|
// duration = chrono::duration_cast<chrono::microseconds>(t3 - t2).count();
|
|
// cout << " symbolic jaccard sim: " << symSim << " after "
|
|
// << (double)duration / 1000.0 << " ms" << endl;
|
|
// double symDist = o1->second.Distance_ALL(o2->second, stj::TRIVIAL);
|
|
// auto t4 = chrono::high_resolution_clock::now();
|
|
// duration = chrono::duration_cast<chrono::microseconds>(t4 - t3).count();
|
|
// cout << " symbolic edit distance: " << symDist << " after "
|
|
// << (double)duration / 1000.0 << " ms" << endl;
|
|
return spaDist * alpha + symDist * (1.0 - alpha);
|
|
}
|
|
|
|
/*
|
|
6.4 ~getTypeNo~
|
|
|
|
Returns a number for supported types, -1 if not supported.
|
|
|
|
*/
|
|
typedef Point t1;
|
|
typedef CcString t2;
|
|
typedef CcInt t3;
|
|
typedef CcReal t4;
|
|
typedef Rectangle<1> t5;
|
|
typedef Rectangle<2> t6;
|
|
typedef Rectangle<3> t7;
|
|
typedef Rectangle<4> t8;
|
|
typedef Rectangle<8> t9;
|
|
typedef temporalalgebra::MPoint t10;
|
|
typedef temporalalgebra::CUPoint t11;
|
|
typedef temporalalgebra::CMPoint t12;
|
|
|
|
int getTypeNo(ListExpr type, int expectedNumbers){
|
|
assert(expectedNumbers==12);
|
|
if(nl->ToString(type) == Tuple::BasicType()){return 12;}
|
|
if( t1::checkType(type)){ return 0;}
|
|
if( t2::checkType(type)){ return 1;}
|
|
if( t3::checkType(type) ){ return 2;}
|
|
if( t4::checkType(type)){ return 3; }
|
|
if( t5::checkType(type)){ return 4;}
|
|
if( t6::checkType(type)){ return 5;}
|
|
if( t7::checkType(type)){ return 6;}
|
|
if( t8::checkType(type)){ return 7;}
|
|
if( t9::checkType(type)){ return 8;}
|
|
if(t10::checkType(type)){ return 9;}
|
|
if(t11::checkType(type)){ return 10;}
|
|
if(t12::checkType(type)){ return 11;}
|
|
return -1;
|
|
}
|
|
|
|
string BasicType(){
|
|
return "mtree";
|
|
}
|
|
|
|
bool checkType(ListExpr type, ListExpr subtype, string basicType) {
|
|
if (!nl->HasLength(type,2)) {
|
|
return false;
|
|
}
|
|
if (!listutils::isSymbol(nl->First(type), basicType)) {
|
|
return false;
|
|
}
|
|
if(getTypeNo(subtype, 12) < 0){
|
|
return false;
|
|
}
|
|
return nl->Equal(nl->Second(type), subtype);
|
|
}
|
|
|
|
bool checkType(ListExpr type, ListExpr subtype) {
|
|
return checkType(type, subtype, BasicType());
|
|
}
|
|
|
|
bool checkTypeN(ListExpr type, ListExpr subtype) {
|
|
return checkType(type, subtype, "ntree");
|
|
}
|
|
|
|
void increaseCounter(const string& objName, const int numberToBeAdded) {
|
|
SecondoCatalog* sc = SecondoSystem::GetCatalog();
|
|
Word counterW;
|
|
bool defined = false;
|
|
bool exists = sc->GetObject(objName, counterW, defined);
|
|
ListExpr currentType = sc->GetObjectTypeExpr(objName);
|
|
if (!CcInt::checkType(currentType) || !defined) {
|
|
sc->DeleteObject(objName);
|
|
}
|
|
if (!exists || !CcInt::checkType(currentType) || !defined) {
|
|
counterW.addr = new CcInt(true, numberToBeAdded);
|
|
sc->InsertObject(objName, CcInt::BasicType(),
|
|
nl->SymbolAtom(CcInt::BasicType()), counterW, true);
|
|
}
|
|
else {
|
|
int counter = ((CcInt*)counterW.addr)->GetValue() + numberToBeAdded;
|
|
((CcInt*)counterW.addr)->Set(true, counter);
|
|
sc->ModifyObject(objName, counterW);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
3.9 class ~DistStorage~, with a struct used to hash a pair of any kind
|
|
|
|
*/
|
|
struct hash_pair {
|
|
template <class T1, class T2>
|
|
size_t operator()(const std::pair<T1, T2>& p) const {
|
|
auto hash1 = std::hash<T1>{}(p.first);
|
|
auto hash2 = std::hash<T2>{}(p.second);
|
|
return hash1 ^ hash2;
|
|
}
|
|
};
|
|
|
|
class DistStorage {
|
|
public:
|
|
DistStorage() : noDistFunCalls(0) {}
|
|
|
|
~DistStorage() {
|
|
clear();
|
|
}
|
|
|
|
double retrieveDist(const TupleId& tid1, const TupleId& tid2) const {
|
|
assert(tid1 <= tid2);
|
|
auto it = storedDists.find(std::make_pair(tid1, tid2));
|
|
if (it == storedDists.end()) { // not found
|
|
// cout << "NOT FOUND dist(" << tid1 << ", " << tid2 << ")" << endl;
|
|
return -1.0;
|
|
}
|
|
// cout << "FOUND dist(" << tid1 << ", " << tid2 << ") = " << it->second
|
|
// << endl;
|
|
return it->second;
|
|
}
|
|
|
|
void storeDist(const TupleId& tid1, const TupleId& tid2, const double dist) {
|
|
storedDists[std::make_pair(tid1, tid2)] = dist;
|
|
// cout << " COMPUTED and STORED dist(" << tid1 << ", " << tid2 << ") = "
|
|
// << dist << " ... # " << storedDists.size() << endl;
|
|
}
|
|
|
|
size_t size() const {
|
|
return storedDists.size();
|
|
}
|
|
|
|
void clear() {
|
|
storedDists.clear();
|
|
noDistFunCalls = 0;
|
|
}
|
|
|
|
void increment() {
|
|
noDistFunCalls++;
|
|
}
|
|
|
|
int getNoDistFunCalls() const {
|
|
return noDistFunCalls;
|
|
}
|
|
|
|
private:
|
|
int noDistFunCalls;
|
|
std::unordered_map<std::pair<TupleId,TupleId>, double, hash_pair> storedDists;
|
|
};
|
|
|
|
template<class T>
|
|
class StdDistComp{
|
|
public:
|
|
|
|
StdDistComp(Geoid* _geoid){
|
|
geoid = _geoid?(Geoid*)_geoid->Clone():0;
|
|
}
|
|
|
|
StdDistComp(const StdDistComp& src){
|
|
geoid = src.geoid?(Geoid*)src.geoid->Copy():0;
|
|
}
|
|
|
|
StdDistComp& operator=(const StdDistComp&src){
|
|
if(geoid) geoid->DeleteIfAllowed();
|
|
geoid = src.geoid?(Geoid*)src.geoid->Copy():0;
|
|
}
|
|
|
|
|
|
~StdDistComp(){
|
|
if(geoid){
|
|
geoid->DeleteIfAllowed();
|
|
}
|
|
}
|
|
|
|
|
|
double operator()(const MTreeEntry<T>& o1, const MTreeEntry<T>& o2) {
|
|
TupleId tid1 = std::min(o1.getTid(), o2.getTid());
|
|
TupleId tid2 = std::max(o1.getTid(), o2.getTid());
|
|
double dist = distStorage.retrieveDist(tid1, tid2);
|
|
if (dist < 0.0) {
|
|
const T* t1 = o1.getKey();
|
|
const T* t2 = o2.getKey();
|
|
dist = mtreehelper::distance(t1, t2, geoid);
|
|
distStorage.increment();
|
|
distStorage.storeDist(tid1, tid2, dist);
|
|
}
|
|
return dist;
|
|
}
|
|
// double operator()(const pair<T,TupleId>& o1,
|
|
// const pair<T,TupleId>& o2){
|
|
// return mtreehelper::distance(&o1.first,&o2.first, geoid);
|
|
// }
|
|
|
|
ostream& print( const MTreeEntry<T>& e, ostream& o){
|
|
o << "<("; e.getKey()->Print(o); o << ", " << e.getTid() << ")>";
|
|
return o;
|
|
}
|
|
|
|
ostream& print(const MTreeEntry<T>& e, const bool printContents,ostream& o){
|
|
if (printContents) {
|
|
return print(e, o);
|
|
}
|
|
o << e.getTid();
|
|
return o;
|
|
}
|
|
|
|
Geoid* getGeoid() const {
|
|
return geoid;
|
|
}
|
|
|
|
void reset(){} // not sureA
|
|
|
|
size_t distStorageSize() const {
|
|
return distStorage.size();
|
|
}
|
|
|
|
int getNoDistFunCalls() const {
|
|
return distStorage.getNoDistFunCalls();
|
|
}
|
|
|
|
protected:
|
|
Geoid* geoid;
|
|
DistStorage distStorage;
|
|
};
|
|
|
|
template<class T, class U>
|
|
class StdDistCompExt : public StdDistComp<pair<T, U> > {
|
|
public:
|
|
StdDistCompExt(Geoid* _geoid, double _alpha) :
|
|
StdDistComp<pair<T, U> >(_geoid), alpha(_alpha) {}
|
|
|
|
StdDistCompExt(const StdDistCompExt& src) :
|
|
StdDistComp<pair<T, U> >(src), alpha(src.alpha) {}
|
|
|
|
StdDistCompExt& operator=(const StdDistCompExt& src) {
|
|
if (this->geoid) {
|
|
this->geoid->DeleteIfAllowed();
|
|
}
|
|
((StdDistComp<pair<T, U> >*)this)->geoid = src.geoid ?
|
|
(Geoid*)src.geoid->Copy() : 0;
|
|
alpha = src.alpha;
|
|
}
|
|
|
|
~StdDistCompExt() {}
|
|
|
|
|
|
ostream& print(const MTreeEntry<pair<T, U> >& p, ostream& o) {
|
|
o << "< <";
|
|
p.getKey()->first.Print(o);
|
|
o << ", ";
|
|
p.getKey()->second.Print(o);
|
|
o << ">, " << p.getTid() << ">";
|
|
return o;
|
|
}
|
|
|
|
double operator()(const MTreeEntry<pair<T, U> >& o1,
|
|
const MTreeEntry<pair<T, U> >& o2) {
|
|
TupleId tid1 = std::min(o1.getTid(), o2.getTid());
|
|
TupleId tid2 = std::max(o1.getTid(), o2.getTid());
|
|
double dist = this->distStorage.retrieveDist(tid1, tid2);
|
|
if (dist < 0.0) {
|
|
const pair<T, U>* p1 = o1.getKey();
|
|
const pair<T, U>* p2 = o2.getKey();
|
|
dist = mtreehelper::distance(p1, p2, alpha,
|
|
((StdDistComp<pair<T, U> >*)this)->getGeoid());
|
|
StdDistComp<pair<T, U> >::distStorage.increment();
|
|
this->distStorage.storeDist(tid1, tid2, dist);
|
|
}
|
|
return dist;
|
|
}
|
|
|
|
private:
|
|
double alpha;
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
Some functions for getting a certain memory object by name.
|
|
The name may be given as a CcString or as a Mem instance.
|
|
A lot of checkes ensure correctness of operations. If one of
|
|
the test failes, the result will be 0 , otherwise a
|
|
pointer to the memory object.
|
|
|
|
*/
|
|
|
|
template<class T>
|
|
memAVLtree* getAVLtree(T* treeN, ListExpr subtype){
|
|
if(!treeN->IsDefined()){
|
|
return 0;
|
|
}
|
|
string treen = treeN->GetValue();
|
|
if(!catalog->isMMOnlyObject(treen) || !catalog->isAccessible(treen)){
|
|
return 0;
|
|
}
|
|
ListExpr treet = nl->Second(catalog->getMMObjectTypeExpr(treen));
|
|
if(!MemoryAVLObject::checkType(treet)){
|
|
return 0;
|
|
}
|
|
if(!nl->Equal(nl->Second(treet),subtype)){
|
|
return 0;
|
|
}
|
|
MemoryAVLObject* mao = (MemoryAVLObject*)catalog->getMMObject(treen);
|
|
return mao->getAVLtree();
|
|
}
|
|
|
|
template<class T>
|
|
memAVLtree* getAVLtree(T* treeN){
|
|
if(!treeN->IsDefined()){
|
|
return 0;
|
|
}
|
|
string treen = treeN->GetValue();
|
|
if(!catalog->isMMOnlyObject(treen) || !catalog->isAccessible(treen)){
|
|
return 0;
|
|
}
|
|
ListExpr treet = nl->Second(catalog->getMMObjectTypeExpr(treen));
|
|
if(!MemoryAVLObject::checkType(treet)){
|
|
return 0;
|
|
}
|
|
MemoryAVLObject* mao = (MemoryAVLObject*)catalog->getMMObject(treen);
|
|
return mao->getAVLtree();
|
|
}
|
|
|
|
template<>
|
|
memAVLtree* getAVLtree(MPointer* tree, ListExpr subtype){
|
|
MemoryObject* ptr = (*tree)();
|
|
return ((MemoryAVLObject*)ptr)->getAVLtree();
|
|
}
|
|
|
|
template<>
|
|
memAVLtree* getAVLtree(MPointer* tree){
|
|
MemoryObject* ptr = (*tree)();
|
|
return ((MemoryAVLObject*)ptr)->getAVLtree();
|
|
}
|
|
|
|
|
|
template<class T>
|
|
MemoryRelObject* getMemRel(T* relN){
|
|
|
|
if(!relN->IsDefined()) { return 0; }
|
|
string reln = relN->GetValue();
|
|
if(!catalog->isMMOnlyObject(reln) || !catalog->isAccessible(reln)) {
|
|
return 0;
|
|
}
|
|
ListExpr relType = nl->Second(catalog->getMMObjectTypeExpr(reln));
|
|
|
|
if(!Relation::checkType(relType)) { return 0; }
|
|
|
|
return (MemoryRelObject*) catalog->getMMObject(reln);
|
|
}
|
|
|
|
template<>
|
|
MemoryRelObject* getMemRel( MPointer* rel){
|
|
return (MemoryRelObject*) ((*rel)());
|
|
}
|
|
|
|
|
|
|
|
template<class T>
|
|
MemoryRelObject* getMemRel(T* relN, ListExpr tupleType, string& error) {
|
|
if(!relN->IsDefined()) {
|
|
error = "Relation name not defined";
|
|
return 0;
|
|
}
|
|
|
|
string reln = relN->GetValue();
|
|
if(!catalog->isMMOnlyObject(reln) || !catalog->isAccessible(reln)){
|
|
error ="relation '"+reln+"' not known or not accessible";
|
|
return 0;
|
|
}
|
|
ListExpr relType = nl->Second(catalog->getMMObjectTypeExpr(reln));
|
|
|
|
if(!Relation::checkType(relType)){
|
|
error = "main memory object '"+reln+"' is not a relation";
|
|
return 0;
|
|
}
|
|
if(!nl->Equal(nl->Second(relType), tupleType)){
|
|
error = string("memory relation has an unexpected tuple type \n")
|
|
+ "expected: " + nl->ToString(tupleType) +"\n"
|
|
+ "found : " + nl->ToString(nl->Second(relType));
|
|
return 0;
|
|
}
|
|
error="";
|
|
return (MemoryRelObject*) catalog->getMMObject(reln);
|
|
}
|
|
|
|
|
|
template<>
|
|
MemoryRelObject* getMemRel(MPointer* rel, ListExpr tupleType, string& error) {
|
|
return (MemoryRelObject*) ((*rel)());
|
|
}
|
|
|
|
|
|
|
|
template<class T>
|
|
MemoryRelObject* getMemRel(T* relN, ListExpr tupleType) {
|
|
string dummy;
|
|
return getMemRel(relN, tupleType, dummy);
|
|
}
|
|
|
|
template<>
|
|
MemoryRelObject* getMemRel(MPointer* rel, ListExpr tupleType) {
|
|
string dummy;
|
|
return getMemRel(rel, tupleType, dummy);
|
|
}
|
|
|
|
template<class T>
|
|
MemoryORelObject* getMemORel(T* relN, ListExpr tupleType){
|
|
if(!relN->IsDefined()){
|
|
return 0;
|
|
}
|
|
string reln = relN->GetValue();
|
|
if(!catalog->isMMOnlyObject(reln) || !catalog->isAccessible(reln)){
|
|
return 0;
|
|
}
|
|
ListExpr relType = nl->Second(catalog->getMMObjectTypeExpr(reln));
|
|
|
|
if(!listutils::isOrelDescription(relType)){
|
|
return 0;
|
|
}
|
|
return (MemoryORelObject*) catalog->getMMObject(reln);
|
|
}
|
|
|
|
template<>
|
|
MemoryORelObject* getMemORel(MPointer* rel, ListExpr tupleType){
|
|
return (MemoryORelObject*) ((*rel)());
|
|
}
|
|
|
|
|
|
template<class T>
|
|
MemoryGraphObject* getMemGraph(T* aN){
|
|
if(!aN->IsDefined()){
|
|
return 0;
|
|
}
|
|
std::string an = aN->GetValue();
|
|
if(!catalog->isMMOnlyObject(an) || !catalog->isAccessible(an)){
|
|
return 0;
|
|
}
|
|
ListExpr type = nl->Second(catalog->getMMObjectTypeExpr(an));
|
|
if(!MemoryGraphObject::checkType(type)){
|
|
return 0;
|
|
}
|
|
|
|
return (MemoryGraphObject*) catalog->getMMObject(an);
|
|
}
|
|
|
|
template<>
|
|
MemoryGraphObject* getMemGraph(MPointer* a){
|
|
return (MemoryGraphObject*) ((*a)());
|
|
}
|
|
|
|
template<class T>
|
|
MemoryAttributeObject* getMemAttribute(T* aN, ListExpr _type){
|
|
if(!aN->IsDefined()){
|
|
return 0;
|
|
}
|
|
string an = aN->GetValue();
|
|
if(!catalog->isMMOnlyObject(an) || !catalog->isAccessible(an)){
|
|
return 0;
|
|
}
|
|
ListExpr type = nl->Second(catalog->getMMObjectTypeExpr(an));
|
|
if(!Attribute::checkType(type)){
|
|
return 0;
|
|
}
|
|
if(!nl->Equal(type,_type)){
|
|
return 0;
|
|
}
|
|
return (MemoryAttributeObject*) catalog->getMMObject(an);
|
|
}
|
|
|
|
template<>
|
|
MemoryAttributeObject* getMemAttribute(MPointer* a, ListExpr _type){
|
|
return (MemoryAttributeObject*) ((*a)());
|
|
}
|
|
|
|
template<class T, int dim>
|
|
MemoryRtreeObject<dim>* getRtree(T* tN){
|
|
if(!tN->IsDefined()){
|
|
return 0;
|
|
}
|
|
string tn = tN->GetValue();
|
|
if(!catalog->isMMOnlyObject(tn)){
|
|
// because we store only rectangle, we do'nt have to check
|
|
// accessibility
|
|
return 0;
|
|
}
|
|
ListExpr type = nl->Second(catalog->getMMObjectTypeExpr(tn));
|
|
if(!rtreehelper::checkType(type,dim)){
|
|
return 0;
|
|
}
|
|
return (MemoryRtreeObject<dim>*) catalog->getMMObject(tn);
|
|
}
|
|
|
|
|
|
template<class T, int dim>
|
|
MemoryRtreeObject<dim>* getRtree(MPointer* p){
|
|
return (MemoryRtreeObject<dim>*) ((*p)());
|
|
}
|
|
|
|
template<int dim>
|
|
MemoryRtreeObject<dim>* getRtree(MPointer* t){
|
|
return (MemoryRtreeObject<dim>*) ((*t)());
|
|
}
|
|
|
|
|
|
template<class T, class K>
|
|
MemoryMtreeObject<K, StdDistComp<K> >* getMtree(T* name){
|
|
if(!name->IsDefined()){
|
|
return 0;
|
|
}
|
|
string n = name->GetValue();
|
|
if(!catalog->isMMOnlyObject(n)){
|
|
return 0;
|
|
}
|
|
ListExpr type = nl->Second(catalog->getMMObjectTypeExpr(n));
|
|
if(!MemoryMtreeObject<K, StdDistComp<K> >::checkType(type)){
|
|
return 0;
|
|
}
|
|
if(!K::checkType(nl->Second(type))){
|
|
return 0;
|
|
}
|
|
return (MemoryMtreeObject<K, StdDistComp<K> >*)
|
|
catalog->getMMObject(n);
|
|
}
|
|
|
|
template<class T, class K, class L>
|
|
MemoryMtreeObject<pair<K, L>, StdDistCompExt<K, L> >* getMtree(T* name) {
|
|
if (!name->IsDefined()) {
|
|
return 0;
|
|
}
|
|
string n = name->GetValue();
|
|
if (!catalog->isMMOnlyObject(n)) {
|
|
return 0;
|
|
}
|
|
ListExpr type = nl->Second(catalog->getMMObjectTypeExpr(n));
|
|
cout << "type is " << nl->ToString(type);
|
|
if (!MemoryMtreeObject<Tuple, StdDistCompExt<K, L> >::checkType(type)) {
|
|
return 0;
|
|
}
|
|
if (!Tuple::checkType(nl->Second(type))) {
|
|
return 0;
|
|
}
|
|
return (MemoryMtreeObject<pair<K, L>, StdDistCompExt<K, L> >*)
|
|
catalog->getMMObject(n);
|
|
}
|
|
|
|
template<class T, class K>
|
|
MemoryMtreeObject<K, StdDistComp<K> >* getMtree(MPointer* t){
|
|
return (MemoryMtreeObject<K, StdDistComp<K> >*) ((*t)());
|
|
}
|
|
|
|
template<class T, class K, class L>
|
|
MemoryMtreeObject<pair<K, L>, StdDistCompExt<K, L> >* getMtree(MPointer* t) {
|
|
return (MemoryMtreeObject<pair<K, L>, StdDistCompExt<K, L> >*)((*t)());
|
|
}
|
|
|
|
template<class T, class K>
|
|
MemoryNtreeObject<K, StdDistComp<K> >* getNtree(T* name) {
|
|
if(!name->IsDefined()){
|
|
return 0;
|
|
}
|
|
string n = name->GetValue();
|
|
if(!catalog->isMMOnlyObject(n)){
|
|
return 0;
|
|
}
|
|
ListExpr type = nl->Second(catalog->getMMObjectTypeExpr(n));
|
|
if(!MemoryNtreeObject<K, StdDistComp<K> >::checkType(type)){
|
|
return 0;
|
|
}
|
|
if(!K::checkType(nl->Second(type))){
|
|
return 0;
|
|
}
|
|
return (MemoryNtreeObject<K, StdDistComp<K> >*)catalog->getMMObject(n);
|
|
}
|
|
|
|
template<class T, class K, class L>
|
|
MemoryNtreeObject<pair<K, L>, StdDistCompExt<K, L> >* getNtree(T* name) {
|
|
if (!name->IsDefined()) {
|
|
return 0;
|
|
}
|
|
string n = name->GetValue();
|
|
if (!catalog->isMMOnlyObject(n)) {
|
|
return 0;
|
|
}
|
|
ListExpr type = nl->Second(catalog->getMMObjectTypeExpr(n));
|
|
cout << "type is " << nl->ToString(type);
|
|
if (!MemoryNtreeObject<Tuple, StdDistCompExt<K, L> >::checkType(type)) {
|
|
return 0;
|
|
}
|
|
if (!Tuple::checkType(nl->Second(type))) {
|
|
return 0;
|
|
}
|
|
return (MemoryNtreeObject<pair<K, L>, StdDistCompExt<K, L> >*)
|
|
catalog->getMMObject(n);
|
|
}
|
|
|
|
template<class T, class K>
|
|
MemoryNtreeObject<K, StdDistComp<K> >* getNtree(MPointer* t){
|
|
return (MemoryNtreeObject<K, StdDistComp<K> >*) ((*t)());
|
|
}
|
|
|
|
template<class T, class K, class L>
|
|
MemoryNtreeObject<pair<K, L>, StdDistCompExt<K, L> >* getNtree(MPointer* t) {
|
|
return (MemoryNtreeObject<pair<K, L>, StdDistCompExt<K, L> >*)((*t)());
|
|
}
|
|
|
|
template<class T>
|
|
MemoryTTreeObject* getTtree(T* treeN){
|
|
if(!treeN->IsDefined()){
|
|
return 0;
|
|
}
|
|
string treen = treeN->GetValue();
|
|
if(!catalog->isMMOnlyObject(treen) || !catalog->isAccessible(treen)){
|
|
return 0;
|
|
}
|
|
ListExpr treet = nl->Second(catalog->getMMObjectTypeExpr(treen));
|
|
if(!MemoryTTreeObject::checkType(treet)){
|
|
return 0;
|
|
}
|
|
return (MemoryTTreeObject*)catalog->getMMObject(treen);
|
|
}
|
|
|
|
template<>
|
|
MemoryTTreeObject* getTtree(MPointer* tree){
|
|
return (MemoryTTreeObject*) ((*tree)());
|
|
}
|
|
|
|
|
|
template<class T>
|
|
MemoryVectorObject* getMVector(T* vecN){
|
|
|
|
if(!vecN->IsDefined()) { return 0; }
|
|
string vecn = vecN->GetValue();
|
|
if(!catalog->isMMOnlyObject(vecn) || !catalog->isAccessible(vecn)) {
|
|
return 0;
|
|
}
|
|
ListExpr vecType = nl->Second(catalog->getMMObjectTypeExpr(vecn));
|
|
|
|
if(!MemoryVectorObject::checkType(vecType)) { return 0; }
|
|
|
|
return (MemoryVectorObject*) catalog->getMMObject(vecn);
|
|
}
|
|
|
|
template<>
|
|
MemoryVectorObject* getMVector( MPointer* vec){
|
|
return (MemoryVectorObject*) ((*vec)());
|
|
}
|
|
|
|
|
|
|
|
template<class T>
|
|
MemoryPQueueObject* getMemoryPQueue(T* qN){
|
|
if(!qN->IsDefined()){
|
|
return 0;
|
|
}
|
|
string qn = qN->GetValue();
|
|
if(!catalog->isMMOnlyObject(qn) || !catalog->isAccessible(qn)){
|
|
return 0;
|
|
}
|
|
ListExpr qt = nl->Second(catalog->getMMObjectTypeExpr(qn));
|
|
if(!MemoryPQueueObject::checkType(qt)){
|
|
return 0;
|
|
}
|
|
return (MemoryPQueueObject*)catalog->getMMObject(qn);
|
|
}
|
|
|
|
template<>
|
|
MemoryPQueueObject* getMemoryPQueue(MPointer* q){
|
|
return (MemoryPQueueObject*) ((*q)());
|
|
}
|
|
|
|
template<class T>
|
|
MemoryStackObject* getMemoryStack(T* qN){
|
|
if(!qN->IsDefined()){
|
|
return 0;
|
|
}
|
|
string qn = qN->GetValue();
|
|
if(!catalog->isMMOnlyObject(qn) || !catalog->isAccessible(qn)){
|
|
return 0;
|
|
}
|
|
ListExpr qt = nl->Second(catalog->getMMObjectTypeExpr(qn));
|
|
if(!MemoryStackObject::checkType(qt)){
|
|
return 0;
|
|
}
|
|
return (MemoryStackObject*)catalog->getMMObject(qn);
|
|
}
|
|
|
|
template<>
|
|
MemoryStackObject* getMemoryStack(MPointer* q){
|
|
return (MemoryStackObject*) ((*q)());
|
|
}
|
|
|
|
|
|
template<class M, class S>
|
|
M* getMemObject(S* qN){
|
|
if(!qN->IsDefined()){
|
|
return 0;
|
|
}
|
|
string qn = qN->GetValue();
|
|
if(!catalog->isMMOnlyObject(qn) || !catalog->isAccessible(qn)){
|
|
return 0;
|
|
}
|
|
ListExpr qt = nl->Second(catalog->getMMObjectTypeExpr(qn));
|
|
if(!M::checkType(qt)){
|
|
return 0;
|
|
}
|
|
return (M*)catalog->getMMObject(qn);
|
|
}
|
|
|
|
|
|
// same function but without type checking of the graph
|
|
template<class M, class S>
|
|
M* getMemObject2(S* qN){
|
|
if(!qN->IsDefined()){
|
|
return 0;
|
|
}
|
|
string qn = qN->GetValue();
|
|
if(!catalog->isMMOnlyObject(qn) || !catalog->isAccessible(qn)){
|
|
return 0;
|
|
}
|
|
return (M*)catalog->getMMObject(qn);
|
|
}
|
|
|
|
|
|
template<class M>
|
|
M* getMemObject(MPointer* t){
|
|
return (M*) ((*t)());
|
|
}
|
|
|
|
template<class M>
|
|
M* getMemObject2(MPointer* t){
|
|
return (M*) ((*t)());
|
|
}
|
|
|
|
/*
|
|
Function returning the current database name.
|
|
|
|
*/
|
|
|
|
string getDBname() {
|
|
SecondoSystem* sys = SecondoSystem::GetInstance();
|
|
return sys->GetDatabaseName();
|
|
}
|
|
|
|
template<class T>
|
|
T* computeValue(ListExpr expression){
|
|
Word queryResult;
|
|
string typeString = "";
|
|
string errorString = "";
|
|
bool correct;
|
|
bool evaluable;
|
|
bool defined;
|
|
bool isFunction;
|
|
// use the queryprocessor for executing the expression
|
|
try{
|
|
qp->ExecuteQuery(expression, queryResult,
|
|
typeString, errorString, correct,
|
|
evaluable, defined, isFunction);
|
|
// check correctness of the expression
|
|
if(!correct || !evaluable || !defined || isFunction){
|
|
assert(queryResult.addr == 0);
|
|
return 0;
|
|
}
|
|
T* fn = (T*) queryResult.addr;
|
|
return fn;
|
|
} catch(...){
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
This function extract the type information from a
|
|
memory object. If the type is given as mem object,
|
|
just this type is set to be the result. Otherwise type
|
|
has to be a CcString having the given value.
|
|
In case of an error (missing objects or whatever), the
|
|
result will be false and some errorsmessage is set.
|
|
In the other case, the reuslt is true, errMsg is keept unchanged
|
|
and result will have the type in the memory.
|
|
|
|
*/
|
|
|
|
bool getMemTypeFromString(ListExpr type, ListExpr value,
|
|
ListExpr & result, string& error,
|
|
bool allowComplex){
|
|
if(!CcString::checkType(type)){
|
|
error = "not of type string";
|
|
return false;
|
|
}
|
|
string n = "";
|
|
if(nl->AtomType(value)==StringType){
|
|
n = nl->StringValue(value);
|
|
} else {
|
|
if(!allowComplex){
|
|
error = "only constant strings supported";
|
|
return false;
|
|
}
|
|
CcString* N = computeValue<CcString>(value);
|
|
if(!N){
|
|
error = "could not compute result for " +nl->ToString(value);
|
|
return false;
|
|
}
|
|
if(!N->IsDefined()){
|
|
N->DeleteIfAllowed();
|
|
error = "Undefined name for memory object";
|
|
return false;
|
|
}
|
|
n = N->GetValue();
|
|
N->DeleteIfAllowed();
|
|
}
|
|
|
|
if(!catalog->isMMOnlyObject(n)){
|
|
error = n + " is not a memory object";
|
|
return false;
|
|
}
|
|
if(!catalog->isAccessible(n)){
|
|
error = n + " is not accessible";
|
|
return false;
|
|
}
|
|
result = catalog->getMMObjectTypeExpr(n);
|
|
if(!Mem::checkType(result)){
|
|
error = "internal error: memory object " + n + " not of type mem";
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
inline bool getMemTypeFromString(ListExpr typevalue,
|
|
ListExpr & result, string& error,
|
|
bool allowComplex = false){
|
|
return getMemTypeFromString(nl->First(typevalue), nl->Second(typevalue),
|
|
result,error,allowComplex);
|
|
}
|
|
/*
|
|
some functions related to strings.
|
|
|
|
*/
|
|
|
|
string rtrim(string s, const string& delim = " \t\r\n")
|
|
{
|
|
string::size_type last = s.find_last_not_of(delim.c_str());
|
|
return last == string::npos ? "" : s.erase(last + 1);
|
|
}
|
|
|
|
string ltrim(string s, const string& delim = " \t\r\n")
|
|
{
|
|
return s.erase(0, s.find_first_not_of(delim.c_str()));
|
|
}
|
|
|
|
string trim(string s, const string& delim = " \t\r\n")
|
|
{
|
|
return ltrim(rtrim(s, delim), delim);
|
|
}
|
|
|
|
/*
|
|
|
|
5 Creating Operators
|
|
|
|
5.1 Operators ~memload~ and ~memloadflob~
|
|
|
|
Load a persistent relation into main memory. If there is not enough space
|
|
it breaks up. The created ~MemoryRelObject~ or ~MemoryORelOBject~
|
|
is usable but not complete.
|
|
|
|
5.1.1 Type Mapping Functions of operator ~memload~
|
|
|
|
|
|
*/
|
|
ListExpr memloadTM(ListExpr args) {
|
|
|
|
if (nl->ListLength(args)!=1){
|
|
return listutils::typeError("wrong number of arguments");
|
|
}
|
|
ListExpr sourceType = nl->First(args);
|
|
// check for allowed types
|
|
if( !Attribute::checkType(sourceType)
|
|
&& !Relation::checkType(sourceType)
|
|
&& !OrderedRelation::checkType(sourceType)){
|
|
return listutils::typeError("only rel, orel, and DATA are supported");
|
|
}
|
|
return MPointer::wrapType(Mem::wrapType(sourceType));
|
|
}
|
|
|
|
|
|
/*
|
|
5.1.3 The Value Mapping Functions of operator ~memload~
|
|
|
|
*/
|
|
template<bool flob>
|
|
int memloadVMRel (Word* args, Word& result,
|
|
int message, Word& local, Supplier s) {
|
|
|
|
GenericRelation* r= static_cast<Relation*>( args[0].addr );
|
|
MemoryRelObject* mmRelObject = new MemoryRelObject();
|
|
ListExpr objectTypeExpr = nl->Second(nl->Second( qp->GetType(s)));
|
|
bool memloadSucceeded = mmRelObject->relToVector(r,
|
|
objectTypeExpr,
|
|
getDBname(),
|
|
flob);
|
|
result = qp->ResultStorage(s);
|
|
MPointer* mp = (MPointer*) result.addr;
|
|
if(memloadSucceeded){
|
|
mp->setPointer(mmRelObject);
|
|
} else {
|
|
mp->setPointer(0);
|
|
}
|
|
// deletion control now by mpointer
|
|
mmRelObject->deleteIfAllowed();
|
|
return 0;
|
|
}
|
|
|
|
template<bool flob>
|
|
int memloadVMORel (Word* args, Word& result,
|
|
int message, Word& local, Supplier s) {
|
|
|
|
GenericRelation* r= static_cast<OrderedRelation*>(args[0].addr);
|
|
MemoryORelObject* mmORelObject = new MemoryORelObject();
|
|
// expected orel description
|
|
ListExpr objectTypeExpr = nl->Second(nl->Second(qp->GetType(s)));
|
|
bool memloadSucceeded = mmORelObject->relToTree(
|
|
r,
|
|
objectTypeExpr,
|
|
getDBname(), flob);
|
|
result = qp->ResultStorage(s);
|
|
MPointer* mp = (MPointer*) result.addr;
|
|
if(memloadSucceeded){
|
|
mp->setPointer(mmORelObject);
|
|
} else {
|
|
mp->setPointer(0);
|
|
}
|
|
mmORelObject->deleteIfAllowed();
|
|
return 0;
|
|
}
|
|
|
|
|
|
template<bool flob>
|
|
int memloadVMAttr (Word* args, Word& result,
|
|
int message, Word& local, Supplier s) {
|
|
|
|
Attribute* attr = (Attribute*)args[0].addr;
|
|
MemoryAttributeObject* mmA = new MemoryAttributeObject();
|
|
ListExpr objectTypeExpr = nl->Second(nl->Second(qp->GetType(s)));
|
|
bool memloadSucceeded = mmA->attrToMM(attr, objectTypeExpr,
|
|
getDBname(),flob);
|
|
|
|
result = qp->ResultStorage(s);
|
|
MPointer* mp = (MPointer*) result.addr;
|
|
if(memloadSucceeded){
|
|
mp->setPointer(mmA);
|
|
} else {
|
|
mp->setPointer(0);
|
|
}
|
|
mmA->deleteIfAllowed();
|
|
return 0;
|
|
}
|
|
|
|
ValueMapping memloadVM[] = {
|
|
memloadVMAttr<false>,
|
|
memloadVMRel<false>,
|
|
memloadVMORel<false>
|
|
};
|
|
|
|
int memloadSelect(ListExpr args){
|
|
ListExpr a1 = nl->First(args);
|
|
if(Attribute::checkType(a1)) return 0;
|
|
if(Relation::checkType(a1)) return 1;
|
|
if(OrderedRelation::checkType(a1)) return 2;
|
|
return -1;
|
|
}
|
|
|
|
OperatorSpec memloadSpec(
|
|
" P -> mpointer(mem(P)) , P in {DATA, rel, orel} ",
|
|
" memload(_)",
|
|
" Converts a peristent object into a memory representation. "
|
|
" Flob will keept persistent.",
|
|
" let mten = memload(ten)"
|
|
);
|
|
|
|
Operator memloadOp(
|
|
"memload",
|
|
memloadSpec.getStr(),
|
|
3,
|
|
memloadVM,
|
|
memloadSelect,
|
|
memloadTM
|
|
);
|
|
|
|
ValueMapping memloadflobVM[] = {
|
|
memloadVMAttr<true>,
|
|
memloadVMRel<true>,
|
|
memloadVMORel<true>
|
|
};
|
|
|
|
OperatorSpec memloadflobSpec(
|
|
" P -> mpointer(mem(P)) , P in {DATA, rel, orel} ",
|
|
" memloadflob(_)",
|
|
" Converts a peristent object into a memory representation. "
|
|
" Flobs will also transferred into main memory.",
|
|
" let mten = memloadflob(ten)"
|
|
);
|
|
|
|
|
|
Operator memloadflobOp(
|
|
"memloadflob",
|
|
memloadflobSpec.getStr(),
|
|
3,
|
|
memloadflobVM,
|
|
memloadSelect,
|
|
memloadTM
|
|
);
|
|
|
|
|
|
/*
|
|
5.3 Operator ~meminit~
|
|
|
|
Initialises the main memory which is used within the main memory algebra.
|
|
The default value is 256MB.
|
|
The maximum value is limited by the value set in ~SecondoConfig.ini~.
|
|
If the wanted value is smaller then the memory that is already in use,
|
|
the value will be set to the smallest possible value
|
|
without deleting any main memory objects.
|
|
|
|
*/
|
|
|
|
/*
|
|
5.3.1 Type Mapping Functions of operator ~meminit~ (int->int)
|
|
|
|
*/
|
|
|
|
ListExpr meminitTypeMap(ListExpr args)
|
|
{
|
|
if(nl->ListLength(args)!=1){
|
|
return listutils::typeError("wrong number of arguments");
|
|
}
|
|
if (!CcInt::checkType(nl->First(args))) {
|
|
return listutils::typeError("int expected");
|
|
}
|
|
return listutils::basicSymbol<CcInt>();
|
|
}
|
|
|
|
|
|
/*
|
|
|
|
5.3.3 The Value Mapping Functions of operator ~meminit~
|
|
|
|
*/
|
|
|
|
int meminitValMap (Word* args, Word& result,
|
|
int message, Word& local, Supplier s) {
|
|
|
|
int maxSystemMainMemory = qp->GetMemorySize(s);
|
|
int newMainMemorySize = ((CcInt*)args[0].addr)->GetIntval();
|
|
int res=0;
|
|
|
|
if (newMainMemorySize<0){
|
|
res=catalog->getMemSizeTotal();
|
|
}
|
|
else if ((double)newMainMemorySize <
|
|
(catalog->getUsedMemSize()/1024.0/1024.0)){
|
|
res = (catalog->getUsedMemSize()/1024.0/1024.0)+1;
|
|
catalog->setMemSizeTotal
|
|
(catalog->getUsedMemSize()/1024.0/1024.0+1);
|
|
}
|
|
else if (newMainMemorySize>maxSystemMainMemory){
|
|
res = maxSystemMainMemory;
|
|
catalog->setMemSizeTotal(maxSystemMainMemory);
|
|
}
|
|
else {
|
|
res = newMainMemorySize;
|
|
catalog->setMemSizeTotal(newMainMemorySize);
|
|
}
|
|
|
|
result = qp->ResultStorage(s);
|
|
CcInt* b = static_cast<CcInt*>(result.addr);
|
|
b->Set(true, res);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
|
|
5.3.4 Description of operator ~meminit~
|
|
|
|
*/
|
|
|
|
OperatorSpec meminitSpec(
|
|
"int -> int",
|
|
"meminit(_)",
|
|
"initialises the main memory, the maximum size "
|
|
" is limited by the global memory which is set in SecondoConfig.ini",
|
|
"query meminit(256)"
|
|
);
|
|
|
|
/*
|
|
|
|
5.3.5 Instance of operator ~meminit~
|
|
|
|
*/
|
|
|
|
Operator meminitOp (
|
|
"meminit",
|
|
meminitSpec.getStr(),
|
|
meminitValMap,
|
|
Operator::SimpleSelect,
|
|
meminitTypeMap
|
|
);
|
|
|
|
|
|
/*
|
|
5.4 Operator ~mfeed~
|
|
|
|
~mfeed~ produces a stream of tuples from a main memory relation or
|
|
ordered relation, similar to the ~feed~-operator
|
|
|
|
5.4.1 Type Mapping Functions of operator ~mfeed~ (string -> stream(Tuple))
|
|
|
|
*/
|
|
|
|
ListExpr mfeedTypeMap(ListExpr args) {
|
|
|
|
if(nl->ListLength(args)!=1){
|
|
return listutils::typeError("wrong number of arguments");
|
|
}
|
|
ListExpr a1 = nl->First(args);
|
|
if(MPointer::checkType(a1)){
|
|
a1 = nl->Second(a1);
|
|
}
|
|
if(!Mem::checkType(a1)){
|
|
return listutils::typeError("argument is not a memory object");
|
|
}
|
|
a1 = nl->Second(a1); // remove mem
|
|
if( !Relation::checkType(a1)
|
|
&& !listutils::isOrelDescription(a1)){
|
|
return listutils::typeError(
|
|
"memory object is not a relation or ordered relation");
|
|
}
|
|
return nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()),
|
|
nl->Second(a1));
|
|
}
|
|
|
|
|
|
/*
|
|
|
|
5.4.3 The Value Mapping Functions of operator ~mfeed~
|
|
|
|
*/
|
|
|
|
|
|
class mfeedInfo{
|
|
public:
|
|
mfeedInfo(vector<Tuple*>* _rel) : rel(_rel), orel(0), pos(0) { }
|
|
|
|
mfeedInfo(ttree::TTree<TupleWrap,TupleComp>* _orel) :
|
|
rel(0),orel(_orel),pos(0) {
|
|
iter = orel->begin();
|
|
}
|
|
|
|
~mfeedInfo() {}
|
|
|
|
Tuple* next() {
|
|
Tuple* res;
|
|
if(rel){
|
|
while(pos < rel->size()){
|
|
res = (*rel)[pos];
|
|
pos++;
|
|
if(res){
|
|
res->SetTupleId(pos);
|
|
res->IncReference();
|
|
return res;
|
|
}
|
|
}
|
|
return 0;
|
|
} else {
|
|
while(!iter.end()) {
|
|
res = (*iter).getPointer();
|
|
iter++;
|
|
if(res){
|
|
res->IncReference();
|
|
return res;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
private:
|
|
vector<Tuple*>* rel;
|
|
ttree::TTree<TupleWrap,TupleComp>* orel;
|
|
size_t pos;
|
|
ttree::Iterator<TupleWrap,TupleComp> iter;
|
|
};
|
|
|
|
|
|
template<bool ordered>
|
|
int mfeedValMapMem (Word* args, Word& result,
|
|
int message, Word& local, Supplier s) {
|
|
|
|
mfeedInfo* li = (mfeedInfo*) local.addr;
|
|
|
|
switch (message) {
|
|
|
|
case OPEN: {
|
|
|
|
if(li) {
|
|
delete li;
|
|
local.addr=0;
|
|
}
|
|
|
|
Mem* oN = (Mem*) args[0].addr;
|
|
if(!oN->IsDefined()){
|
|
return 0;
|
|
}
|
|
if(ordered){
|
|
MemoryORelObject* orel = getMemORel(oN, nl->Second(qp->GetType(s)));
|
|
if(!orel) {
|
|
return 0;
|
|
}
|
|
local.addr= new mfeedInfo(orel->getmmorel());
|
|
return 0;
|
|
} else {
|
|
MemoryRelObject* rel = getMemRel(oN);
|
|
if(!rel) {
|
|
return 0;
|
|
}
|
|
local.addr= new mfeedInfo(rel->getmmrel());
|
|
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;
|
|
}
|
|
|
|
|
|
|
|
template<bool ordered>
|
|
int mfeedValMapMPointer (Word* args, Word& result,
|
|
int message, Word& local, Supplier s) {
|
|
|
|
mfeedInfo* li = (mfeedInfo*) local.addr;
|
|
switch(message){
|
|
case OPEN:{
|
|
if(li){
|
|
delete li;
|
|
}
|
|
MPointer* p = (MPointer*) args[0].addr;
|
|
if(ordered){
|
|
MemoryORelObject* orel = (MemoryORelObject*) (*p)() ;
|
|
if(!orel) {
|
|
return 0;
|
|
}
|
|
local.addr= new mfeedInfo(orel->getmmorel());
|
|
} else {
|
|
MemoryRelObject* a =(MemoryRelObject*) (*p)();
|
|
if(!a){
|
|
return 0;
|
|
}
|
|
local.addr= new mfeedInfo(a->getmmrel());
|
|
}
|
|
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;
|
|
}
|
|
|
|
|
|
ValueMapping mfeedVM[] = {
|
|
mfeedValMapMem<false>,
|
|
mfeedValMapMem<true>,
|
|
mfeedValMapMPointer<false>,
|
|
mfeedValMapMPointer<true>,
|
|
};
|
|
|
|
int mfeedSelect(ListExpr args) {
|
|
ListExpr a1 = nl->First(args);
|
|
int o1 = 0;
|
|
if(MPointer::checkType(a1)){
|
|
o1 = 2;
|
|
a1 = nl->Second(a1);
|
|
}
|
|
a1 = nl->Second(a1);
|
|
int o2 = Relation::checkType(a1)?0:1;
|
|
return o1 + o2;
|
|
}
|
|
|
|
|
|
/*
|
|
|
|
5.4.4 Description of operator ~mfeed~
|
|
|
|
|
|
*/
|
|
|
|
OperatorSpec mfeedSpec(
|
|
"{MREL, MOREL} -> stream(Tuple), ",
|
|
"_ mfeed",
|
|
"produces a stream from a main memory (ordered) relation",
|
|
"query mten mfeed"
|
|
);
|
|
|
|
/*
|
|
|
|
5.4.5 Instance of operator ~mfeed~
|
|
|
|
*/
|
|
|
|
Operator mfeedOp (
|
|
"mfeed",
|
|
mfeedSpec.getStr(),
|
|
4,
|
|
mfeedVM,
|
|
mfeedSelect,
|
|
mfeedTypeMap
|
|
);
|
|
|
|
|
|
/*
|
|
5.5 Operator gettuples
|
|
|
|
This operator gets a stream of tuple ids,
|
|
and a main memory relation and returns the
|
|
tuples from the ids out of the relation.
|
|
|
|
*/
|
|
ListExpr gettuplesTM(ListExpr args){
|
|
string err ="stream(X) x {string, mem(rel(tuple))} expected";
|
|
if(!nl->HasLength(args,2)){
|
|
return listutils::typeError(err + " (wrong number of args)");
|
|
}
|
|
ListExpr a2;
|
|
if(!getMemSubType(nl->Second(args),a2)){
|
|
return listutils::typeError("second argument is not a memory object");
|
|
}
|
|
if(!Relation::checkType(a2)){
|
|
return listutils::typeError(err + " (second arg is not a "
|
|
"memory relation.)");
|
|
}
|
|
ListExpr a1 = nl->First(args);
|
|
if(Stream<TupleIdentifier>::checkType(a1)){
|
|
return nl->TwoElemList( listutils::basicSymbol<Stream<Tuple> >(),
|
|
nl->Second(a2));
|
|
}
|
|
// second variant accepts a stream of tuples containing a tupleID
|
|
if(!Stream<Tuple>::checkType(a1)){
|
|
return listutils::typeError("1st arg is neither a stream of "
|
|
"tids nor a stream of tuples");
|
|
}
|
|
ListExpr attrList = nl->Second(nl->Second(a1));
|
|
int index = 0;
|
|
int tidIndex = 0;
|
|
ListExpr iattr = nl->TheEmptyList();
|
|
ListExpr last = nl->TheEmptyList();
|
|
set<string> usednames;
|
|
bool first = true;
|
|
|
|
|
|
while(!nl->IsEmpty(attrList)){
|
|
ListExpr attr = nl->First(attrList);
|
|
attrList = nl->Rest(attrList);
|
|
index++;
|
|
if(TupleIdentifier::checkType(nl->Second(attr))){
|
|
if(tidIndex!=0){
|
|
return listutils::typeError("incoming tuple stream contains "
|
|
"more than one tid attribute");
|
|
}
|
|
tidIndex = index;
|
|
} else {
|
|
if(first){
|
|
iattr = nl->OneElemList(attr);
|
|
last = iattr;
|
|
first = false;
|
|
} else {
|
|
last = nl->Append(last, attr);
|
|
}
|
|
}
|
|
}
|
|
if(!tidIndex){
|
|
return listutils::typeError("incoming tuple stream does not "
|
|
"contains an attribute of type tid");
|
|
}
|
|
ListExpr relAttrList = nl->Second(nl->Second(a2));
|
|
ListExpr resAttrList = listutils::concat(iattr, relAttrList);
|
|
|
|
if(!listutils::isAttrList(resAttrList)){
|
|
return listutils::typeError("found name conflicts");
|
|
}
|
|
|
|
ListExpr ret = nl->ThreeElemList(nl->SymbolAtom(Symbols::APPEND()),
|
|
nl->OneElemList(nl->IntAtom(tidIndex-1)),
|
|
nl->TwoElemList(
|
|
listutils::basicSymbol<Stream<Tuple> >(),
|
|
nl->TwoElemList(
|
|
listutils::basicSymbol<Tuple>(),
|
|
resAttrList)));
|
|
return ret;
|
|
}
|
|
|
|
|
|
class gettuplesInfo{
|
|
public:
|
|
gettuplesInfo(Word& _stream, MemoryRelObject* _rel):
|
|
stream(_stream), rel(_rel->getmmrel()){
|
|
stream.open();
|
|
}
|
|
|
|
~gettuplesInfo(){
|
|
stream.close();
|
|
}
|
|
|
|
Tuple* next(){
|
|
TupleIdentifier* tid;
|
|
while((tid=stream.request())){
|
|
if(!tid->IsDefined()){
|
|
tid->DeleteIfAllowed();
|
|
} else {
|
|
TupleId id = tid->GetTid();
|
|
tid->DeleteIfAllowed();
|
|
if(id>0 && id<=rel->size()){
|
|
Tuple* res = (*rel)[id-1];
|
|
if(res){ // ignore deleted tuples
|
|
res->IncReference();
|
|
res->SetTupleId(id);
|
|
return res;
|
|
} else {
|
|
// cout << "ignore deleted tuple" << endl;
|
|
;
|
|
}
|
|
} else {
|
|
// cout << "ignore id " << id << endl;
|
|
;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
private:
|
|
Stream<TupleIdentifier> stream;
|
|
vector<Tuple*>* rel;
|
|
};
|
|
|
|
template<class T>
|
|
int gettuplesVMT (Word* args, Word& result,
|
|
int message, Word& local, Supplier s) {
|
|
|
|
gettuplesInfo* li = (gettuplesInfo*) local.addr;
|
|
switch(message){
|
|
case OPEN :{
|
|
if(li){
|
|
delete li;
|
|
local.addr = 0;
|
|
}
|
|
T* n = (T*) args[1].addr;
|
|
MemoryRelObject* rel = getMemRel(n,nl->Second(qp->GetType(s)));
|
|
if(!rel){
|
|
return 0;
|
|
}
|
|
local.addr = new gettuplesInfo(args[0], rel);
|
|
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;
|
|
}
|
|
|
|
|
|
class gettuplesInfoUnwrap{
|
|
public:
|
|
gettuplesInfoUnwrap(Word& _stream, MemoryRelObject* _rel, int _tidpos,
|
|
ListExpr resTupleType):
|
|
stream(_stream), rel(_rel->getmmrel()), tidpos(_tidpos){
|
|
stream.open();
|
|
tt = new TupleType(resTupleType);
|
|
}
|
|
|
|
~gettuplesInfoUnwrap(){
|
|
stream.close();
|
|
tt->DeleteIfAllowed();
|
|
}
|
|
|
|
Tuple* next(){
|
|
Tuple* inTuple;
|
|
while((inTuple=stream.request())){
|
|
TupleIdentifier* tid = (TupleIdentifier*)
|
|
inTuple->GetAttribute(tidpos);
|
|
if(!tid->IsDefined()){
|
|
inTuple->DeleteIfAllowed();
|
|
} else {
|
|
TupleId id = tid->GetTid();
|
|
if(id<1 || id > rel->size()){
|
|
inTuple->DeleteIfAllowed();
|
|
} else {
|
|
Tuple* relTuple = rel->at(id-1);
|
|
if(!relTuple){
|
|
inTuple->DeleteIfAllowed();
|
|
} else {
|
|
Tuple* resTuple = createResTuple(inTuple,relTuple);
|
|
inTuple->DeleteIfAllowed();
|
|
return resTuple;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
private:
|
|
Stream<Tuple> stream;
|
|
vector<Tuple*>* rel;
|
|
int tidpos;
|
|
TupleType* tt;
|
|
|
|
Tuple* createResTuple(Tuple* inTuple, Tuple* relTuple){
|
|
Tuple* resTuple = new Tuple(tt);
|
|
// copy attributes before tid from intuple to restuple
|
|
for(int i=0; i < tidpos; i++){
|
|
resTuple->CopyAttribute(i,inTuple,i);
|
|
}
|
|
// copy attributes after tidpos from intuple to restuple
|
|
for(int i=tidpos+1;i<inTuple->GetNoAttributes(); i++){
|
|
resTuple->CopyAttribute(i,inTuple,i-1);
|
|
}
|
|
// copy attributes from relTuple to resTuple
|
|
for(int i=0;i<relTuple->GetNoAttributes(); i++){
|
|
resTuple->CopyAttribute(i, relTuple,
|
|
i + inTuple->GetNoAttributes()-1);
|
|
}
|
|
return resTuple;
|
|
}
|
|
};
|
|
|
|
|
|
template<class T>
|
|
int gettuplesUnwrapVMT (Word* args, Word& result,
|
|
int message, Word& local, Supplier s) {
|
|
|
|
gettuplesInfoUnwrap* li = (gettuplesInfoUnwrap*) local.addr;
|
|
switch(message){
|
|
case OPEN :{
|
|
if(li){
|
|
delete li;
|
|
local.addr = 0;
|
|
}
|
|
T* n = (T*) args[1].addr;
|
|
MemoryRelObject* rel = getMemRel(n);
|
|
if(!rel){
|
|
return 0;
|
|
}
|
|
int tidpos = ((CcInt*)args[2].addr)->GetValue();
|
|
ListExpr tt = nl->Second(GetTupleResultType(s));
|
|
local.addr = new gettuplesInfoUnwrap(args[0], rel,tidpos,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 -1;
|
|
}
|
|
|
|
|
|
|
|
ValueMapping gettuplesVM[] = {
|
|
gettuplesVMT<Mem>,
|
|
gettuplesVMT<MPointer>,
|
|
gettuplesUnwrapVMT<Mem>,
|
|
gettuplesUnwrapVMT<MPointer>
|
|
|
|
};
|
|
|
|
int gettuplesSelect(ListExpr args){
|
|
int n2 = -1;
|
|
ListExpr a2 = nl->Second(args);
|
|
if(Mem::checkType(a2)) n2 = 0;
|
|
if(MPointer::checkType(a2)) n2 = 1;
|
|
if(n2<0) return -1;
|
|
|
|
int n1 = Stream<TupleIdentifier>::checkType(nl->First(args))?0:2;
|
|
return n1+n2;
|
|
}
|
|
|
|
OperatorSpec gettuplesSpec(
|
|
"stream({tid,tuple}) x MREL -> stream(tuple(X)), "
|
|
"MREL represented as mem or mpointer",
|
|
"_ _ gettuples",
|
|
"Retrieves tuples from a main memory relation whose ids are "
|
|
"specified in the incoming stream. If the incoming stream is a tuple stream,"
|
|
"exactly one attribute must be of type tid. Thius attribute is used to "
|
|
"extract the tuples from the main memory relation. The tid-attribute is "
|
|
"removed from the incoming stream and the tuple from the relation is "
|
|
"appended to the remaining tuples",
|
|
"query strassen_Name mdistScan2[mstr] mstrassen gettuples consume"
|
|
);
|
|
|
|
Operator gettuplesOp(
|
|
"gettuples",
|
|
gettuplesSpec.getStr(),
|
|
4,
|
|
gettuplesVM,
|
|
gettuplesSelect,
|
|
gettuplesTM
|
|
);
|
|
|
|
|
|
/*
|
|
5.7 Operator ~memobject~
|
|
|
|
~memobject~ gets a name of a main memory object and return a persistent version
|
|
|
|
5.7.1 Type Mapping Functions of operator ~memobject~ (string -> m:MEMLOADABLE)
|
|
|
|
*/
|
|
ListExpr memobjectTypeMap(ListExpr args) {
|
|
if(nl->ListLength(args)!=1){
|
|
return listutils::typeError("wrong number of arguments");
|
|
}
|
|
ListExpr arg1 = nl->First(args);
|
|
if(MPointer::checkType(arg1)){
|
|
arg1 = nl->Second(arg1);
|
|
}
|
|
if(!Mem::checkType(arg1)){
|
|
return listutils::typeError("Argument is not a memory object");
|
|
}
|
|
ListExpr subtype = nl->Second(arg1);
|
|
if( !Attribute::checkType(subtype)
|
|
&& !Relation::checkType(subtype)){
|
|
return listutils::typeError("only rel and DATA are supported");
|
|
}
|
|
return subtype;
|
|
}
|
|
|
|
|
|
/*
|
|
|
|
5.7.3 The Value Mapping Functions of operator ~memobject~
|
|
|
|
*/
|
|
template<class T>
|
|
int memobjectValMap (Word* args, Word& result,
|
|
int message, Word& local, Supplier s) {
|
|
result = qp->ResultStorage(s);
|
|
ListExpr resType = qp->GetType(s);
|
|
T* oN = (T*) args[0].addr;
|
|
if(Attribute::checkType(resType)){ // Attribute
|
|
MemoryAttributeObject* mao = getMemAttribute(oN, resType);
|
|
if(!mao){
|
|
((Attribute*) result.addr)->SetDefined(false);
|
|
return 0;
|
|
}
|
|
((Attribute*) result.addr)->CopyFrom(mao->getAttributeObject());
|
|
return 0;
|
|
} else if(Relation::checkType(resType)){ // relation
|
|
GenericRelation* r = (GenericRelation*) result.addr;
|
|
if(r->GetNoTuples() > 0) {
|
|
r->Clear();
|
|
}
|
|
|
|
MemoryRelObject* mro = getMemRel(oN, nl->Second(resType));
|
|
if(!mro){
|
|
return 0;
|
|
}
|
|
vector<Tuple*>* relation = mro->getmmrel();
|
|
vector<Tuple*>::iterator it;
|
|
it=relation->begin();
|
|
|
|
while( it!=relation->end()){
|
|
Tuple* tup = *it;
|
|
r->AppendTuple(tup);
|
|
it++;
|
|
}
|
|
return 0;
|
|
}
|
|
assert(false); // unsupported type
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
|
|
5.7.4 Description of operator ~memobject~
|
|
|
|
*/
|
|
OperatorSpec memobjectSpec(
|
|
" mem(X) | mpointer(mem(X)) ->X , X in {DATA, rel}",
|
|
"memobject (_)",
|
|
"returns a persistent object created from a main memory object",
|
|
"query memobject (mTrains100)"
|
|
);
|
|
|
|
/*
|
|
5.7.5 Value Mapping Array and Selection
|
|
|
|
*/
|
|
ValueMapping memobjectVM[] = {
|
|
memobjectValMap<Mem>,
|
|
memobjectValMap<MPointer>
|
|
};
|
|
|
|
int memobjectSelect(ListExpr args){
|
|
ListExpr a = nl->First(args);
|
|
if(Mem::checkType(a)) return 0;
|
|
if(MPointer::checkType(a)) return 1;
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
|
|
5.7.5 Instance of operator ~memobject~
|
|
|
|
*/
|
|
|
|
Operator memobjectOp (
|
|
"memobject",
|
|
memobjectSpec.getStr(),
|
|
2,
|
|
memobjectVM,
|
|
memobjectSelect,
|
|
memobjectTypeMap
|
|
);
|
|
|
|
/*
|
|
|
|
5.8 Operator ~memgetcatalog~
|
|
|
|
Returns a ~stream(Tuple)~.
|
|
Each tuple describes one element of the main memory catalog.
|
|
|
|
|
|
5.8.1 Type Mapping Functions of operator ~memgetcatalog~ ( -> stream(Tuple) )
|
|
|
|
*/
|
|
|
|
|
|
ListExpr memgetcatalogTypeMap(ListExpr args)
|
|
{
|
|
if(nl->ListLength(args)!=0){
|
|
return listutils::typeError("no argument expected");
|
|
}
|
|
|
|
string stringlist = "(stream(tuple((TotalMB int)"
|
|
"(UsedMB real)(Name string)"
|
|
"(ObjectType text)(ObjSizeInB string)(ObjSizeInMB real)"
|
|
"(Database string)(Accessible bool)(FlobsLoaded bool)"
|
|
"(NoReferences int ))))";
|
|
|
|
ListExpr res =0;
|
|
if(nl->ReadFromString(stringlist, res)){};
|
|
return res;
|
|
}
|
|
|
|
|
|
/*
|
|
|
|
5.8.3 The Value Mapping Functions of operator ~memgetcatalog~
|
|
|
|
*/
|
|
|
|
class memgetcatalogInfo{
|
|
public:
|
|
|
|
memgetcatalogInfo(ListExpr _resultType){
|
|
|
|
tt = new TupleType(nl->Second(_resultType));
|
|
memContents = catalog->getMemContent();
|
|
it = memContents->begin();
|
|
};
|
|
~memgetcatalogInfo(){
|
|
tt->DeleteIfAllowed();
|
|
}
|
|
|
|
string long_to_string(unsigned long value) {
|
|
std::ostringstream stream;
|
|
stream << value;
|
|
return stream.str();
|
|
}
|
|
|
|
Tuple* next(){
|
|
if(it==memContents->end()) {
|
|
return 0;
|
|
}
|
|
string name = it->first;
|
|
MemoryObject* memobj = it->second;
|
|
string objTyp ="nn";
|
|
|
|
ListExpr objectType = catalog->getMMObjectTypeExpr(name);
|
|
objTyp = nl->ToString(objectType);
|
|
|
|
Tuple *tup = new Tuple( tt );
|
|
|
|
CcInt* totalMB = new CcInt (true, catalog->getMemSizeTotal());
|
|
CcReal* usedMB =
|
|
new CcReal(true, (double)catalog->getUsedMemSize()/1024.0/1024.0);
|
|
CcString* objectName = new CcString(true,name);
|
|
FText* oT = new FText(true,objTyp);
|
|
int64_t objectMem = memobj?memobj->getMemSize():0;
|
|
CcString* memSizeB = new CcString(true, long_to_string(objectMem));
|
|
CcReal* memSizeMB =
|
|
new CcReal(true, (double)objectMem/1024.0/1024.0);
|
|
string db = memobj?memobj->getDatabase():"none";
|
|
CcString* database = new CcString(true,db);
|
|
bool access = memobj
|
|
? (memobj->getDatabase()==getDBname()) || (memobj->hasflob())
|
|
: true;
|
|
CcBool* accessible = new CcBool(true, access);
|
|
bool flob = memobj?memobj->hasflob():false;
|
|
CcBool* flobs = new CcBool(true, flob);
|
|
|
|
int norefs = memobj?memobj->getNoReferences():0;
|
|
|
|
|
|
tup->PutAttribute(0,totalMB);
|
|
tup->PutAttribute(1,usedMB);
|
|
tup->PutAttribute(2,objectName);
|
|
tup->PutAttribute(3,oT);
|
|
tup->PutAttribute(4,memSizeB);
|
|
tup->PutAttribute(5,memSizeMB);
|
|
tup->PutAttribute(6,database);
|
|
tup->PutAttribute(7,accessible);
|
|
tup->PutAttribute(8,flobs);
|
|
tup->PutAttribute(9,new CcInt(norefs));
|
|
it++;
|
|
return tup;
|
|
}
|
|
private:
|
|
|
|
map<string, MemoryObject*>* memContents;
|
|
map<string, MemoryObject*>::iterator it;
|
|
TupleType* tt;
|
|
|
|
};
|
|
|
|
|
|
int memgetcatalogValMap (Word* args, Word& result,
|
|
int message, Word& local, Supplier s) {
|
|
|
|
|
|
memgetcatalogInfo* li = (memgetcatalogInfo*) local.addr;
|
|
|
|
switch (message)
|
|
{
|
|
case OPEN: {
|
|
if(li){
|
|
delete li;
|
|
local.addr=0;
|
|
|
|
}
|
|
ListExpr resultType;
|
|
resultType = GetTupleResultType( s );
|
|
local.addr= new memgetcatalogInfo(resultType);
|
|
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 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
5.8.4 Description of operator ~memgetcatalog~
|
|
|
|
*/
|
|
|
|
OperatorSpec memgetcatalogSpec(
|
|
" -> stream(Tuple)",
|
|
"memgetcatalog()",
|
|
"returns a stream(Tuple) with information about main memory objects",
|
|
"query memgetcatalog()"
|
|
);
|
|
|
|
/*
|
|
|
|
5.8.5 Instance of operator ~memgetcatalog~
|
|
|
|
*/
|
|
|
|
Operator memgetcatalogOp (
|
|
"memgetcatalog",
|
|
memgetcatalogSpec.getStr(),
|
|
memgetcatalogValMap,
|
|
Operator::SimpleSelect,
|
|
memgetcatalogTypeMap
|
|
);
|
|
|
|
|
|
|
|
/*
|
|
5.10 Operator ~mcreateRtree~
|
|
creates a an mmRTree over a given main memory relation
|
|
or a stream of tuples
|
|
|
|
5.10.1 TypeMapping
|
|
|
|
mpointer(mem(REL(...))) x IDENT -> mpointer(rtree(dim)), REL in rel,orel
|
|
stream(tuple(... TID)) x IDENT -> mpointer(rtree(dim))
|
|
|
|
*/
|
|
|
|
ListExpr mcreatertreeTM(ListExpr args){
|
|
|
|
if(!nl->HasLength(args,2)){
|
|
return listutils::typeError("two arguments expected");
|
|
}
|
|
ListExpr arg2 = nl->Second(args);
|
|
if(nl->AtomType(arg2)!=SymbolType){
|
|
return listutils::typeError("second argument is not a valid "
|
|
"attribute name");
|
|
}
|
|
|
|
ListExpr arg1 = nl->First(args);
|
|
ListExpr attrList= nl->TheEmptyList();
|
|
int tidIndex = -1;
|
|
if(Stream<Tuple>::checkType(arg1)){
|
|
attrList = nl->Second(nl->Second(arg1));
|
|
ListExpr tid = listutils::basicSymbol<TupleIdentifier>();
|
|
string tidn;
|
|
tidIndex = listutils::findType(attrList, tid, tidn);
|
|
if(!tidIndex){
|
|
return listutils::typeError("no tid found in tuple of stream");
|
|
}
|
|
tidIndex--;
|
|
} else {
|
|
if(!MPointer::checkType(arg1)){
|
|
return listutils::typeError("mcreatertree expects an mpointer to "
|
|
"a relation or a stream of tuples");
|
|
}
|
|
arg1 = nl->Second(arg1); // remove mpointer
|
|
if(!Mem::checkType(arg1)){
|
|
return listutils::typeError("internal error");
|
|
}
|
|
arg1 = nl->Second(arg1); // remove mem
|
|
if(!Relation::checkType(arg1)){
|
|
return listutils::typeError("mcreatertree expects an mpointer to "
|
|
"a relation or a stream of tuples");
|
|
|
|
}
|
|
attrList = nl->Second(nl->Second(arg1));
|
|
}
|
|
|
|
ListExpr attrType;
|
|
string aname = nl->SymbolValue(arg2);
|
|
int attrIndex = listutils::findAttribute(attrList, aname, attrType);
|
|
if(!attrIndex){
|
|
return listutils::typeError("attribute " + aname+ " not found");
|
|
}
|
|
attrIndex--;
|
|
int dim = rtreehelper::getDimension(attrType);
|
|
if(dim < 0){
|
|
return listutils::typeError("cannot determine dimension of attribute "
|
|
+ aname);
|
|
}
|
|
ListExpr resType = MPointer::wrapType(Mem::wrapType(
|
|
rtreehelper::getType(dim)));
|
|
ListExpr appendList;
|
|
if(tidIndex < 0){
|
|
appendList = nl->OneElemList(nl->IntAtom(attrIndex));
|
|
} else {
|
|
appendList = nl->TwoElemList( nl->IntAtom(attrIndex),
|
|
nl->IntAtom(tidIndex));
|
|
}
|
|
return nl->ThreeElemList( nl->SymbolAtom(Symbols::APPEND()),
|
|
appendList,
|
|
resType);
|
|
|
|
}
|
|
|
|
|
|
template<int dim>
|
|
int mcreateRtreeVMMP(Word* args, Word& result,
|
|
int message, Word& local, Supplier s) {
|
|
|
|
result = qp->ResultStorage(s);
|
|
MPointer* res = (MPointer*) result.addr;
|
|
MPointer* arg = (MPointer*) args[0].addr;
|
|
MemoryRelObject* mrel = (MemoryRelObject*) arg->GetValue();
|
|
if(!mrel){
|
|
return 0;
|
|
}
|
|
|
|
std::vector<Tuple*>* v = mrel->getmmrel();
|
|
if(!v){
|
|
return 0;
|
|
}
|
|
|
|
int attrPos = ((CcInt*) args[2].addr)->GetValue();
|
|
|
|
mmrtree::RtreeT<dim, size_t>* tree = new mmrtree::RtreeT<dim, size_t>(4,8);
|
|
for(size_t i = 0;i<v->size();i++){
|
|
Tuple* t = v->at(i);
|
|
if(t){
|
|
Rectangle<dim> r = ((StandardSpatialAttribute<dim>*)
|
|
t->GetAttribute(attrPos))->BoundingBox();
|
|
if(r.IsDefined()){
|
|
tree->insert(r,i);
|
|
}
|
|
}
|
|
}
|
|
MemoryRtreeObject<dim>* mrt = new MemoryRtreeObject<dim>(tree,
|
|
tree->usedMem(),
|
|
nl->ToString(nl->Second(qp->GetType(s))),
|
|
getDBname());
|
|
res->setPointer(mrt);
|
|
mrt->deleteIfAllowed();
|
|
return 0;
|
|
}
|
|
|
|
|
|
template<int dim>
|
|
int mcreateRtreeVMStream(Word* args, Word& result,
|
|
int message, Word& local, Supplier s) {
|
|
|
|
result = qp->ResultStorage(s);
|
|
MPointer* res = (MPointer*) result.addr;
|
|
|
|
int attrPos = ((CcInt*) args[2].addr)->GetValue();
|
|
int tidPos = ((CcInt*) args[3].addr)->GetValue();
|
|
Stream<Tuple> stream(args[0]);
|
|
stream.open();
|
|
mmrtree::RtreeT<dim, size_t>* tree = new mmrtree::RtreeT<dim, size_t>(4,8);
|
|
Tuple* t;
|
|
while( (t = stream.request())){
|
|
Rectangle<dim> r = ((StandardSpatialAttribute<dim>*)
|
|
t->GetAttribute(attrPos))->BoundingBox();
|
|
TupleIdentifier* tid = (TupleIdentifier*) t->GetAttribute(tidPos);
|
|
if(r.IsDefined() && tid->IsDefined()){
|
|
tree->insert(r,tid->GetTid());
|
|
}
|
|
t->DeleteIfAllowed();
|
|
}
|
|
stream.close();
|
|
MemoryRtreeObject<dim>* mrt = new MemoryRtreeObject<dim>(tree,
|
|
tree->usedMem(),
|
|
nl->ToString(nl->Second(qp->GetType(s))),
|
|
getDBname());
|
|
res->setPointer(mrt);
|
|
mrt->deleteIfAllowed();
|
|
return 0;
|
|
}
|
|
|
|
|
|
ValueMapping mcreatertreeVM[] = {
|
|
mcreateRtreeVMStream<2>,
|
|
mcreateRtreeVMStream<3>,
|
|
mcreateRtreeVMStream<4>,
|
|
mcreateRtreeVMStream<8>,
|
|
mcreateRtreeVMMP<2>,
|
|
mcreateRtreeVMMP<3>,
|
|
mcreateRtreeVMMP<4>,
|
|
mcreateRtreeVMMP<8>
|
|
};
|
|
|
|
int mcreatertreeSelect(ListExpr args){
|
|
int o1 = 0;
|
|
ListExpr attrList;
|
|
if(MPointer::checkType(nl->First(args))){
|
|
o1 = 4;
|
|
attrList = nl->Second(nl->Second(nl->Second(nl->Second(nl->First(args)))));
|
|
} else {
|
|
o1 = 0;
|
|
attrList = nl->Second(nl->Second(nl->First(args)));
|
|
}
|
|
string attrName = nl->SymbolValue(nl->Second(args));
|
|
ListExpr attrType;
|
|
listutils::findAttribute(attrList, attrName, attrType);
|
|
int dim = rtreehelper::getDimension(attrType);
|
|
int o2 = 0;
|
|
switch(dim){
|
|
case 2 : o2 = 0; break;
|
|
case 3 : o2 = 1; break;
|
|
case 4 : o2 = 2; break;
|
|
case 8 : o2 = 3; break;
|
|
default: assert(false);
|
|
}
|
|
return o1 + o2;
|
|
}
|
|
|
|
OperatorSpec mcreatertreeSpec(
|
|
" { mpointer(mem(rel(...))), stream(tuple(...)) } x IDENT "
|
|
"-> mpointer(rtree X)",
|
|
" _ createmmrtree[_]",
|
|
" Creates a main memory based rtree over an attribute of a relation "
|
|
"represented as either main memory relation or as a tuple stream.",
|
|
"query mstrassen createmmrtree[GeoData]"
|
|
);
|
|
|
|
|
|
Operator mcreatertreeOp(
|
|
"mcreatertree",
|
|
mcreatertreeSpec.getStr(),
|
|
8,
|
|
mcreatertreeVM,
|
|
mcreatertreeSelect,
|
|
mcreatertreeTM
|
|
);
|
|
|
|
|
|
/*
|
|
5.11 Operator ~memsize~
|
|
|
|
returns the currently set main memory size
|
|
|
|
5.11.1 Type Mapping Functions of operator ~memsize~ (->int)
|
|
|
|
*/
|
|
|
|
ListExpr memsizeTypeMap(ListExpr args)
|
|
{
|
|
|
|
if(nl->ListLength(args)!=0){
|
|
return listutils::typeError("no argument expected");
|
|
}
|
|
|
|
return listutils::basicSymbol<CcInt>();
|
|
}
|
|
|
|
|
|
/*
|
|
|
|
5.11.3 The Value Mapping Functions of operator ~memsize~
|
|
|
|
*/
|
|
|
|
int memsizeValMap (Word* args, Word& result,
|
|
int message, Word& local, Supplier s) {
|
|
|
|
int res = catalog->getMemSizeTotal();
|
|
|
|
result = qp->ResultStorage(s);
|
|
CcInt* b = static_cast<CcInt*>(result.addr);
|
|
b->Set(true, res);
|
|
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
|
|
5.11.4 Description of operator ~memsize~
|
|
|
|
*/
|
|
|
|
OperatorSpec memsizeSpec(
|
|
"-> int",
|
|
"memsize()",
|
|
"returns the currently set main memory size ",
|
|
"query memsize()"
|
|
);
|
|
|
|
/*
|
|
|
|
5.11.5 Instance of operator ~memsize~
|
|
|
|
*/
|
|
|
|
Operator memsizeOp (
|
|
"memsize",
|
|
memsizeSpec.getStr(),
|
|
memsizeValMap,
|
|
Operator::SimpleSelect,
|
|
memsizeTypeMap
|
|
);
|
|
|
|
|
|
|
|
/*
|
|
5.12 Operator ~memclear~
|
|
|
|
deletes all main memory objects
|
|
|
|
5.12.1 Type Mapping Functions of operator ~memclear~ (-> bool)
|
|
|
|
*/
|
|
|
|
ListExpr memclearTypeMap(ListExpr args)
|
|
{
|
|
|
|
if(nl->ListLength(args)!=0){
|
|
return listutils::typeError("no argument expected");
|
|
}
|
|
|
|
return listutils::basicSymbol<CcBool>();
|
|
}
|
|
|
|
|
|
/*
|
|
|
|
5.12.3 The Value Mapping Functions of operator ~memclear~
|
|
|
|
*/
|
|
|
|
int memclearValMap (Word* args, Word& result,
|
|
int message, Word& local, Supplier s) {
|
|
|
|
bool res = false;
|
|
catalog->clear();
|
|
res = true;
|
|
result = qp->ResultStorage(s);
|
|
CcBool* b = static_cast<CcBool*>(result.addr);
|
|
b->Set(true, res);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
|
|
5.12.4 Description of operator ~memclear~
|
|
|
|
*/
|
|
|
|
OperatorSpec memclearSpec(
|
|
"-> bool",
|
|
"memclear()",
|
|
"deletes all main memory objects",
|
|
"query memclear()"
|
|
);
|
|
|
|
/*
|
|
|
|
5.12.5 Instance of operator ~memclear~
|
|
|
|
*/
|
|
|
|
Operator memclearOp (
|
|
"memclear",
|
|
memclearSpec.getStr(),
|
|
memclearValMap,
|
|
Operator::SimpleSelect,
|
|
memclearTypeMap
|
|
);
|
|
|
|
|
|
/*
|
|
5.13 Operator ~meminsert~
|
|
|
|
inserts the tuple of a stream into a existing main memory relation
|
|
|
|
5.13.1 Type Mapping Functions of operator ~meminsert~
|
|
(stream(tuple(x)) x string -> stream(tuple(x))
|
|
the second argument identifies the main memory relation
|
|
|
|
*/
|
|
|
|
ListExpr meminsertTypeMap(ListExpr args)
|
|
{
|
|
if(nl->ListLength(args)!=2){
|
|
return listutils::typeError("two arguments expected");
|
|
}
|
|
|
|
ListExpr stream = nl->First(args);
|
|
|
|
if (!Stream<Tuple>::checkType(stream)) {
|
|
return listutils::typeError
|
|
("stream(Tuple) as first argument expected");
|
|
}
|
|
|
|
ListExpr argSec = nl->Second(args);
|
|
if(MPointer::checkType(argSec)){
|
|
argSec = nl->Second(argSec);
|
|
}
|
|
if(!Mem::checkType(argSec)){
|
|
return listutils::typeError("second arg is not a memory object");
|
|
}
|
|
ListExpr subtype = nl->Second(argSec);
|
|
if(!Relation::checkType(subtype)){
|
|
return listutils::typeError("mem relation expected ");
|
|
}
|
|
if(!nl->Equal(nl->Second(stream), nl->Second(subtype))){
|
|
return listutils::typeError("stream type and mem relation type differ");
|
|
}
|
|
return stream;
|
|
|
|
}
|
|
|
|
|
|
class meminsertInfo{
|
|
public:
|
|
meminsertInfo( Word& w, vector<Tuple*>* _relation, bool _flob):
|
|
stream(w),relation(_relation), flob(_flob){
|
|
stream.open();
|
|
}
|
|
|
|
~meminsertInfo(){
|
|
stream.close();
|
|
}
|
|
|
|
Tuple* next(){
|
|
Tuple* res = stream.request();
|
|
if(!res){
|
|
return 0;
|
|
}
|
|
if(flob){
|
|
res->bringToMemory();
|
|
}
|
|
res->IncReference();
|
|
relation->push_back(res);
|
|
res->SetTupleId(relation->size());
|
|
return res;
|
|
}
|
|
|
|
private:
|
|
Stream<Tuple> stream;
|
|
vector<Tuple*>* relation;
|
|
bool flob;
|
|
|
|
};
|
|
|
|
|
|
/*
|
|
|
|
5.13.3 The Value Mapping Functions of operator ~meminsert~
|
|
|
|
*/
|
|
template<class T, bool tc>
|
|
int meminsertValMap (Word* args, Word& result,
|
|
int message, Word& local, Supplier s) {
|
|
|
|
meminsertInfo* li = (meminsertInfo*) local.addr;
|
|
|
|
switch (message)
|
|
{
|
|
case OPEN: {
|
|
if(li){
|
|
delete li;
|
|
local.addr=0;
|
|
}
|
|
T* oN = (T*) args[1].addr;
|
|
MemoryRelObject* mro = 0;
|
|
if(tc){
|
|
ListExpr tt = nl->Second(qp->GetType(qp->GetSon(s,0)));
|
|
mro = getMemRel(oN,tt);
|
|
} else {
|
|
mro = getMemRel(oN);
|
|
}
|
|
if(!mro){
|
|
return 0;
|
|
}
|
|
local.addr = new meminsertInfo(args[0], mro->getmmrel(),
|
|
mro->hasflob());
|
|
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;
|
|
}
|
|
|
|
ValueMapping meminsertVM[] = {
|
|
meminsertValMap<Mem,true>,
|
|
meminsertValMap<MPointer,false>
|
|
};
|
|
|
|
int meminsertSelect(ListExpr args){
|
|
ListExpr a = nl->Second(args);
|
|
if(Mem::checkType(a)) return 0;
|
|
if(MPointer::checkType(a)) return 1;
|
|
return -1;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
5.13.4 Description of operator ~meminsert~
|
|
|
|
*/
|
|
|
|
OperatorSpec meminsertSpec(
|
|
"stream(Tuple) x {string, mem(rel), mpointer(rel)} -> stream(Tuple)",
|
|
"meminsert(_,_)",
|
|
"inserts the tuples of a stream into an "
|
|
"existing main memory relation",
|
|
"query meminsert (ten feed head[5],'ten') count"
|
|
);
|
|
|
|
/*
|
|
|
|
5.13.5 Instance of operator ~meminsert~
|
|
|
|
*/
|
|
|
|
Operator meminsertOp (
|
|
"meminsert",
|
|
meminsertSpec.getStr(),
|
|
3,
|
|
meminsertVM,
|
|
meminsertSelect,
|
|
meminsertTypeMap
|
|
);
|
|
|
|
/*
|
|
5.14 Operator ~mwindowintersects~
|
|
Uses the given MemoryRtreeObject (as first argument)to find all tuples
|
|
in the given MemoryRelObject (as second argument)
|
|
with intersects the third argument value's bounding box
|
|
|
|
5.14.1 Type Mapping Functions of operator ~mwindowintersects~
|
|
string x string x T -> stream(Tuple)
|
|
where T in {rect<d>} U SPATIAL2D U SPATIAL3D U SPATIAL4D U SPATIAL8D
|
|
|
|
*/
|
|
|
|
ListExpr mwindowintersectsTypeMap(ListExpr args)
|
|
{
|
|
if(nl->ListLength(args)!=3){
|
|
return listutils::typeError("three arguments expected");
|
|
}
|
|
|
|
/* Split argument in three parts */
|
|
ListExpr a1 = nl->First(args);
|
|
ListExpr a2 = nl->Second(args);
|
|
ListExpr a3 = nl->Third(args);
|
|
|
|
string err="MRTREE x MREL x rectX expected";
|
|
|
|
if(MPointer::checkType(a1)){
|
|
a1 = nl->Second(a1);
|
|
}
|
|
if(!Mem::checkType(a1)){
|
|
return listutils::typeError("first arg is not a memory object");
|
|
}
|
|
|
|
if(MPointer::checkType(a2)){
|
|
a2 = nl->Second(a2);
|
|
}
|
|
if(!Mem::checkType(a2)){
|
|
return listutils::typeError("second arg is not a memory object");
|
|
}
|
|
|
|
|
|
ListExpr rtreetype = nl->Second(a1); // remove leading mem
|
|
|
|
if(!rtreehelper::checkType(rtreetype)){
|
|
return listutils::typeError(err + " (first arg is not a mem rtree)");
|
|
}
|
|
|
|
int rtreedim = nl->IntValue(nl->Second(rtreetype));
|
|
|
|
ListExpr relType = nl->Second(a2);
|
|
if(!Relation::checkType(relType)){
|
|
return listutils::typeError(err + " (second argument is not "
|
|
"a memory relation)");
|
|
}
|
|
|
|
int dim2 = rtreehelper::getDimension(a3);
|
|
|
|
if(dim2 < 0){
|
|
return listutils::typeError("third argument not in kind SPATIALxD");
|
|
}
|
|
|
|
if(rtreedim != dim2){
|
|
return listutils::typeError("dimensions of rtree and "
|
|
"search object differ");
|
|
}
|
|
|
|
ListExpr res = nl->TwoElemList(
|
|
listutils::basicSymbol<Stream<Tuple> >(),
|
|
nl->Second(relType));
|
|
return res;
|
|
}
|
|
|
|
|
|
|
|
template<int dim>
|
|
class mwiInfo{
|
|
public:
|
|
mwiInfo( MemoryRtreeObject<dim>* _tree,
|
|
MemoryRelObject* _rel,
|
|
Rectangle<dim>& _box) {
|
|
mmrtree::RtreeT<dim, size_t>* t = _tree->getrtree();
|
|
rel = _rel->getmmrel();
|
|
it = t->find(_box);
|
|
}
|
|
|
|
~mwiInfo(){
|
|
delete it;
|
|
}
|
|
|
|
Tuple* next(){
|
|
Tuple* res = 0;
|
|
while(!res){
|
|
const size_t* indexp = it->next();
|
|
if(!indexp){
|
|
return 0;
|
|
}
|
|
if(*indexp < rel->size()){ // ignores index outside vector
|
|
res = (*rel)[*indexp];
|
|
if(res){ // may be deleted
|
|
res->IncReference();
|
|
}
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
|
|
private:
|
|
vector<Tuple*>* rel;
|
|
typename mmrtree::RtreeT<dim, size_t>::iterator* it;
|
|
};
|
|
|
|
/*
|
|
|
|
5.14.3 The Value Mapping Functions of operator ~mwindowintersects~
|
|
|
|
*/
|
|
template <class T, class R, int dim>
|
|
int mwindowintersectsValMapT (Word* args, Word& result,
|
|
int message, Word& local, Supplier s) {
|
|
|
|
mwiInfo<dim>* li = (mwiInfo<dim>*) local.addr;
|
|
|
|
switch (message)
|
|
{
|
|
case OPEN: {
|
|
if(li){
|
|
delete li;
|
|
local.addr=0;
|
|
}
|
|
T* treeN = (T*) args[0].addr;
|
|
R* relN = (R*) args[1].addr;
|
|
typedef StandardSpatialAttribute<dim> W;
|
|
typedef MemoryRtreeObject<dim> treetype;
|
|
W* window = (W*) args[2].addr;
|
|
ListExpr tupleT = nl->Second(qp->GetType(s));
|
|
MemoryRelObject* mro = getMemRel(relN,tupleT);
|
|
if(!mro){
|
|
return 0;
|
|
}
|
|
treetype* tree = getRtree<T,dim>(treeN);
|
|
if(!tree){
|
|
return 0;
|
|
}
|
|
if(!window->IsDefined()){
|
|
return 0;
|
|
}
|
|
Rectangle<dim> box = window->BoundingBox();
|
|
if(!box.IsDefined()){ // empty spatial object
|
|
return 0;
|
|
}
|
|
local.addr = new mwiInfo<dim>(tree, mro, box);
|
|
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;
|
|
}
|
|
|
|
ValueMapping mwindowintersectsValMap[] =
|
|
{
|
|
mwindowintersectsValMapT<Mem, Mem,2>,
|
|
mwindowintersectsValMapT<Mem, Mem,3>,
|
|
mwindowintersectsValMapT<Mem, Mem,4>,
|
|
mwindowintersectsValMapT<Mem, Mem,8>,
|
|
|
|
mwindowintersectsValMapT<Mem, MPointer,2>,
|
|
mwindowintersectsValMapT<Mem, MPointer,3>,
|
|
mwindowintersectsValMapT<Mem, MPointer,4>,
|
|
mwindowintersectsValMapT<Mem, MPointer,8>,
|
|
|
|
mwindowintersectsValMapT<MPointer, Mem,2>,
|
|
mwindowintersectsValMapT<MPointer, Mem,3>,
|
|
mwindowintersectsValMapT<MPointer, Mem,4>,
|
|
mwindowintersectsValMapT<MPointer, Mem,8>,
|
|
|
|
mwindowintersectsValMapT<MPointer, MPointer,2>,
|
|
mwindowintersectsValMapT<MPointer, MPointer,3>,
|
|
mwindowintersectsValMapT<MPointer, MPointer,4>,
|
|
mwindowintersectsValMapT<MPointer, MPointer,8>,
|
|
};
|
|
|
|
/*
|
|
1.3 Selection method for value mapping array ~mcreateRtree~
|
|
|
|
*/
|
|
int mwindowintersectsSelect(ListExpr args)
|
|
{
|
|
int dim = rtreehelper::getDimension(nl->Third(args));
|
|
int n3 = -1;
|
|
switch (dim){
|
|
case 2 : n3 = 0;break;
|
|
case 3 : n3 = 1;break;
|
|
case 4 : n3 = 2;break;
|
|
case 8 : n3 = 3;break;
|
|
default : return -1;
|
|
}
|
|
|
|
int n1 = -1;
|
|
ListExpr a1 = nl->First(args);
|
|
if(Mem::checkType(a1)) n1 = 0;
|
|
if(MPointer::checkType(a1)) n1 = 1;
|
|
|
|
int n2 = -1;
|
|
ListExpr a2 = nl->Second(args);
|
|
if(Mem::checkType(a2)) n2 = 0;
|
|
if(MPointer::checkType(a2)) n2 = 1;
|
|
|
|
int res = 8*n1 + 4*n2 + n3;
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/*
|
|
|
|
5.14.4 Description of operator ~mwindowintersects~
|
|
|
|
*/
|
|
|
|
OperatorSpec mwindowintersectsSpec(
|
|
"MRTREE x MREL x rectX -> stream(tuple(X)) , where MRTREE, MREL"
|
|
" are represented as mem or mpointer",
|
|
"_ _ mwindowintersects[_]",
|
|
"Uses the given rtree to find all tuples"
|
|
" in the given relation which intersects the "
|
|
" argument value's bounding box.",
|
|
"query mstrassen_GeoData mstrassen mwindowintersects[thecenter] count"
|
|
);
|
|
|
|
/*
|
|
|
|
5.14.5 Instance of operator ~mwindowintersects~
|
|
|
|
*/
|
|
|
|
Operator mwindowintersectsOp (
|
|
"mwindowintersects",
|
|
mwindowintersectsSpec.getStr(),
|
|
16,
|
|
mwindowintersectsValMap,
|
|
mwindowintersectsSelect,
|
|
mwindowintersectsTypeMap
|
|
);
|
|
|
|
|
|
/*
|
|
5.16 Operator mwindowintersectsS
|
|
|
|
*/
|
|
template<bool wrap>
|
|
ListExpr mwindowintersectsSTM(ListExpr args){
|
|
|
|
string err = " {string, memory(rtree <dim> )} x SPATIAL<dim>D expected";
|
|
if(!nl->HasLength(args,2)){
|
|
return listutils::typeError(err + " (wrong number of args)");
|
|
}
|
|
ListExpr a2t = nl->Second(args);
|
|
int dim = rtreehelper::getDimension(a2t);
|
|
if(dim < 0){
|
|
return listutils::typeError(err + " (second arg is not in "
|
|
"kind SPATIALxD)");
|
|
}
|
|
ListExpr a1 = nl->First(args);
|
|
if(MPointer::checkType(a1)){
|
|
a1 = nl->Second(a1);
|
|
}
|
|
if(!Mem::checkType(a1)){
|
|
return listutils::typeError("first arg is not a memory object");
|
|
}
|
|
ListExpr tree = nl->Second(a1);
|
|
if(!rtreehelper::checkType(tree)){
|
|
return listutils::typeError(err + " (first arg is not an r-tree");
|
|
}
|
|
int tdim = nl->IntValue(nl->Second(tree));
|
|
if(dim!=tdim){
|
|
return listutils::typeError(err + "tree and query object have "
|
|
"different dimensions");
|
|
}
|
|
if(!wrap){
|
|
return nl->TwoElemList(
|
|
listutils::basicSymbol<Stream<TupleIdentifier> >(),
|
|
listutils::basicSymbol<TupleIdentifier> ());
|
|
} else {
|
|
ListExpr attrList = nl->OneElemList(
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom("TID"),
|
|
listutils::basicSymbol<TupleIdentifier>()));
|
|
|
|
return nl->TwoElemList( listutils::basicSymbol<Stream<Tuple> >(),
|
|
nl->TwoElemList( listutils::basicSymbol<Tuple>(),
|
|
attrList));
|
|
}
|
|
}
|
|
|
|
template<int dim>
|
|
struct mwindowintersectsSInfo{
|
|
typename mmrtree::RtreeT<dim,size_t>::iterator* it;
|
|
TupleType* tt;
|
|
};
|
|
|
|
|
|
template <int dim, class T, bool wrap>
|
|
int mwindowintersectsSVMT (Word* args, Word& result,
|
|
int message, Word& local, Supplier s) {
|
|
|
|
|
|
mwindowintersectsSInfo<dim>* li = (mwindowintersectsSInfo<dim>*)local.addr;
|
|
|
|
switch(message){
|
|
case OPEN:{
|
|
if(li){
|
|
delete li->it;
|
|
if(li->tt){
|
|
li->tt->DeleteIfAllowed();
|
|
}
|
|
delete li;
|
|
local.addr = 0;
|
|
}
|
|
T* name = (T*) args[0].addr;
|
|
MemoryRtreeObject<dim>* tree = getRtree<T,dim>(name);
|
|
if(!tree){
|
|
return 0;
|
|
}
|
|
typedef StandardSpatialAttribute<dim> boxtype;
|
|
boxtype* o = (boxtype*) args[1].addr;
|
|
if(!o->IsDefined()){
|
|
return 0;
|
|
}
|
|
Rectangle<dim> box = o->BoundingBox();
|
|
if(!box.IsDefined()){ // empty spatial object
|
|
return 0;
|
|
}
|
|
li = new mwindowintersectsSInfo<dim>();
|
|
li->it = tree->getrtree()->find(box);
|
|
if(wrap){
|
|
li->tt = new TupleType( nl->Second(GetTupleResultType(s)));
|
|
} else {
|
|
li->tt = 0;
|
|
}
|
|
local.addr = li;
|
|
return 0;
|
|
}
|
|
case REQUEST : {
|
|
if(!li){
|
|
return CANCEL;
|
|
}
|
|
const size_t* index = li->it->next();
|
|
if(!index){
|
|
result.addr=0;
|
|
} else { // iterator exhausted
|
|
TupleIdentifier* tid = new TupleIdentifier(true,*index);
|
|
if(!wrap){
|
|
result.addr = tid;
|
|
} else {
|
|
Tuple* tuple = new Tuple(li->tt);
|
|
tuple->PutAttribute(0,tid);
|
|
result.addr = tuple;
|
|
}
|
|
}
|
|
return result.addr?YIELD:CANCEL;
|
|
}
|
|
case CLOSE:
|
|
if(li){
|
|
delete li->it;
|
|
if(li->tt){
|
|
li->tt->DeleteIfAllowed();
|
|
}
|
|
delete li;
|
|
local.addr = 0;
|
|
}
|
|
return 0;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
ValueMapping mwindowintersectsSVM[] = {
|
|
mwindowintersectsSVMT<2, Mem, true>,
|
|
mwindowintersectsSVMT<3, Mem, true>,
|
|
mwindowintersectsSVMT<4, Mem, true>,
|
|
mwindowintersectsSVMT<8, Mem, true>,
|
|
mwindowintersectsSVMT<2, MPointer, true>,
|
|
mwindowintersectsSVMT<3, MPointer, true>,
|
|
mwindowintersectsSVMT<4, MPointer, true>,
|
|
mwindowintersectsSVMT<8, MPointer, true>
|
|
};
|
|
|
|
int mwindowintersectsSSelect(ListExpr args){
|
|
int n1 = -1;
|
|
ListExpr a1 = nl->First(args);
|
|
|
|
if(Mem::checkType(a1)) n1=0;
|
|
if(MPointer::checkType(a1)) n1=4;
|
|
|
|
|
|
int dim = rtreehelper::getDimension(nl->Second(args));
|
|
int n2;
|
|
switch(dim){
|
|
case 2 : n2 = 0; break;
|
|
case 3 : n2 = 1; break;
|
|
case 4 : n2 = 2; break;
|
|
case 8 : n2 = 3; break;
|
|
default : assert(false);
|
|
}
|
|
return n1 + n2;
|
|
}
|
|
|
|
|
|
OperatorSpec mwindowintersectsSSpec(
|
|
"MRTREE x SPATIAL<dim>D -> stream(tuple((TID tid))), MRTREE "
|
|
"represented as mem, or mpointer",
|
|
" _ mwindowintersectsS[_]",
|
|
"Returns the tuple ids belonging to rectangles intersecting the "
|
|
"bounding box of the second argument wraped in a tuple. ",
|
|
"query mstrassen_GeoData mwindowintersectsS[ thecenter ] count"
|
|
);
|
|
|
|
Operator mwindowintersectsSOp(
|
|
"mwindowintersectsS",
|
|
mwindowintersectsSSpec.getStr(),
|
|
8,
|
|
mwindowintersectsSVM,
|
|
mwindowintersectsSSelect,
|
|
mwindowintersectsSTM<true>
|
|
);
|
|
|
|
|
|
|
|
/*
|
|
|
|
5.15 Operator ~mconsume~
|
|
|
|
~mconsume~ Collects objects from a stream in a ~MemoryRelObject~
|
|
|
|
5.4.1 Type Mapping Functions of operator ~mconsume~
|
|
(stream(Tuple) -> memoryRelObject)
|
|
|
|
*/
|
|
ListExpr mconsumeTypeMap(ListExpr args)
|
|
{
|
|
if(nl->ListLength(args)!=1){
|
|
return listutils::typeError("(wrong number of arguments)");
|
|
}
|
|
if (!Stream<Tuple>::checkType(nl->First(args))) {
|
|
return listutils::typeError ("stream(tuple) expected!");
|
|
}
|
|
ListExpr ttype = nl->Second(nl->First(args));
|
|
ListExpr relType = nl->TwoElemList(
|
|
nl->SymbolAtom(Relation::BasicType()),
|
|
ttype);
|
|
return MPointer::wrapType(Mem::wrapType(relType));
|
|
}
|
|
|
|
|
|
/*
|
|
|
|
5.15.3 The Value Mapping Functions of operator ~mconsume~
|
|
|
|
*/
|
|
template<bool flob>
|
|
int mconsumeValMap (Word* args, Word& result,
|
|
int message, Word& local, Supplier s){
|
|
result = qp->ResultStorage(s);
|
|
MPointer* mp = (MPointer*)result.addr;
|
|
ListExpr tupleType = nl->Second(nl->Second(qp->GetType(s)));
|
|
MemoryRelObject* mrel = new MemoryRelObject();
|
|
mrel->tupleStreamToRel(args[0], tupleType, getDBname(),flob);
|
|
mp->setPointer(mrel);
|
|
mrel->deleteIfAllowed();
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
|
|
5.15.4 Description of operator ~mconsume~
|
|
|
|
*/
|
|
|
|
OperatorSpec mconsumeSpec(
|
|
"stream(Tuple) -> mpointer(mem(rel(TUPLE)))",
|
|
"_ mconsume",
|
|
"collects the objects from a stream(tuple) into a memory relation",
|
|
"query ten feed mconsume"
|
|
);
|
|
|
|
/*
|
|
|
|
5.15.5 Instance of operator ~mconsume~
|
|
|
|
*/
|
|
|
|
Operator mconsumeOp (
|
|
"mconsume",
|
|
mconsumeSpec.getStr(),
|
|
mconsumeValMap<false>,
|
|
Operator::SimpleSelect,
|
|
mconsumeTypeMap
|
|
);
|
|
|
|
/*
|
|
|
|
5.15.4 Description of operator ~mconsumeflob~
|
|
|
|
*/
|
|
|
|
OperatorSpec mconsumeflobSpec(
|
|
"stream(Tuple) -> mpointer(mem(rel(TUPLE)))",
|
|
"_ mconsumeflob",
|
|
"collects the objects from a stream(tuple) including flobs "
|
|
"into a memory relation",
|
|
"query ten feed mconsumeflob"
|
|
);
|
|
|
|
/*
|
|
|
|
5.15.5 Instance of operator ~mconsume~
|
|
|
|
*/
|
|
|
|
Operator mconsumeflobOp (
|
|
"mconsumeflob",
|
|
mconsumeflobSpec.getStr(),
|
|
mconsumeValMap<true>,
|
|
Operator::SimpleSelect,
|
|
mconsumeTypeMap
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
5.16 Operator ~mcreateAVLtree~
|
|
creates a an AVLTree over a given main memory relation
|
|
|
|
5.16.1 Type Mapping Functions of operator ~mcreateAVLtree~
|
|
|
|
the first parameter identifies the main memory relation, the
|
|
second parameter identifies the attribute
|
|
|
|
another variant accpects a stream of tuple and two
|
|
attribute names. The first one identifies the attribute to
|
|
index, the second one a TID attribute.
|
|
|
|
*/
|
|
|
|
ListExpr mcreateAVLtreeTypeMap(ListExpr args){
|
|
|
|
if(!nl->HasLength(args,2) && !nl->HasLength(args,3)){
|
|
return listutils::typeError("two arguments expected");
|
|
}
|
|
bool isStream = nl->HasLength(args,3);
|
|
|
|
if(nl->AtomType(nl->Second(args))!=SymbolType){
|
|
return listutils::typeError("second arg does not represent a valid "
|
|
"attribute name");
|
|
}
|
|
string err = "expected stream(tuple) x IDENT x INDENT or MREL x IDENT";
|
|
|
|
ListExpr tupleType = nl->TheEmptyList();
|
|
ListExpr attrList = nl->TheEmptyList();
|
|
ListExpr first = nl->First(args);
|
|
int tidIndex = -1;
|
|
if(isStream){
|
|
if(!Stream<Tuple>::checkType(first)){
|
|
return listutils::typeError(err);
|
|
}
|
|
ListExpr third = nl->Third(args);
|
|
if(nl->AtomType(third) != SymbolType){
|
|
return listutils::typeError("third argument is not a valid "
|
|
"attribute name");
|
|
}
|
|
string tidname = nl->SymbolValue(third);
|
|
ListExpr tidType;
|
|
tupleType = nl->Second(first);
|
|
attrList = nl->Second(tupleType);
|
|
tidIndex = listutils::findAttribute(attrList, tidname, tidType);
|
|
if(!tidIndex){
|
|
return listutils::typeError("attribute " + tidname
|
|
+ " is not a member of tuple");
|
|
}
|
|
if(!TupleIdentifier::checkType(tidType)){
|
|
return listutils::typeError("attribute " + tidname
|
|
+ " not of type tid");
|
|
}
|
|
} else {
|
|
if(MPointer::checkType(first)){
|
|
first = nl->Second(first);
|
|
}
|
|
if(!Mem::checkType(first)){
|
|
return listutils::typeError(err);
|
|
}
|
|
ListExpr subType = nl->Second(first);
|
|
if(!Relation::checkType(subType)){
|
|
return listutils::typeError("first arg is not a MREL");
|
|
}
|
|
tupleType = nl->Second(subType);
|
|
attrList = nl->Second(tupleType);
|
|
}
|
|
|
|
string attrName = nl->SymbolValue(nl->Second(args));
|
|
ListExpr attrType;
|
|
int attrIndex = listutils::findAttribute(attrList,attrName,attrType);
|
|
|
|
if(!attrIndex){
|
|
return listutils::typeError(attrName + " is not a member of the tuple");
|
|
}
|
|
|
|
ListExpr resType = MPointer::wrapType(
|
|
Mem::wrapType(
|
|
MemoryAVLObject::wrapType(attrType)));
|
|
|
|
ListExpr appendList;
|
|
if(isStream){
|
|
appendList = nl->TwoElemList( nl->IntAtom(attrIndex-1),
|
|
nl->IntAtom(tidIndex-1));
|
|
} else {
|
|
appendList = nl->OneElemList( nl->IntAtom(attrIndex-1));
|
|
}
|
|
|
|
|
|
return nl->ThreeElemList(
|
|
nl->SymbolAtom(Symbols::APPEND()),
|
|
appendList,
|
|
resType);
|
|
}
|
|
|
|
/*
|
|
|
|
5.16.3 The Value Mapping Functions of operator ~mcreateAVLtree~
|
|
|
|
*/
|
|
MemoryAVLObject* createAVLTree(MemoryRelObject* mmrel, int attrPos,
|
|
ListExpr type){
|
|
bool flob = mmrel->hasflob();
|
|
vector<Tuple*>* relVec = mmrel->getmmrel();
|
|
vector<Tuple*>::iterator it;
|
|
it=relVec->begin();
|
|
unsigned int i=1; // start tuple counting with 1
|
|
|
|
memAVLtree* tree = new memAVLtree();
|
|
Attribute* attr;
|
|
AttrIdPair aPair;
|
|
|
|
size_t usedMainMemory = 0;
|
|
unsigned long availableMemSize = catalog->getAvailableMemSize();
|
|
|
|
while ( it!=relVec->end()){
|
|
Tuple* tup = *it;
|
|
if(tup){
|
|
attr=tup->GetAttribute(attrPos);
|
|
aPair = AttrIdPair(attr,i);
|
|
// size for a pair is 16 bytes, plus an additional pointer 8 bytes
|
|
size_t entrySize = 24;
|
|
if (entrySize<availableMemSize){
|
|
tree->insert(aPair);
|
|
usedMainMemory += (entrySize);
|
|
availableMemSize -= (entrySize);
|
|
i++;
|
|
} else {
|
|
cout<<"there is not enough main memory available"
|
|
" to create an AVLTree"<<endl;
|
|
delete tree;
|
|
return 0;
|
|
}
|
|
}
|
|
it++;
|
|
}
|
|
MemoryAVLObject* avlObject =
|
|
new MemoryAVLObject(tree, usedMainMemory,
|
|
nl->ToString(type),flob, getDBname());
|
|
return avlObject;
|
|
}
|
|
|
|
|
|
|
|
int mcreateAVLtreeVMMem (Word* args, Word& result,
|
|
int message, Word& local, Supplier s) {
|
|
|
|
result = qp->ResultStorage(s);
|
|
MPointer* res = (MPointer*) result.addr;
|
|
|
|
// the main memory relation
|
|
Mem* roN = (Mem*) args[0].addr;
|
|
if(!roN->IsDefined()){
|
|
res->setPointer(0);
|
|
return 0;
|
|
}
|
|
string relObjectName = roN->GetValue();
|
|
|
|
int attrPos = ((CcInt*) args[2].addr)->GetValue();
|
|
|
|
ListExpr memObjectType = catalog->getMMObjectTypeExpr(relObjectName);
|
|
|
|
ListExpr argType = qp->GetType(qp->GetSon(s,0));
|
|
|
|
if(!nl->Equal(memObjectType, argType)){
|
|
cerr << "type stored in catalog and type of mem object differ" << endl;
|
|
cerr << "type of memobject " << argType << endl;
|
|
cerr << "type in catalog " << memObjectType << endl;
|
|
res->setPointer(0);
|
|
return 0;
|
|
}
|
|
|
|
MemoryRelObject* mmrel =
|
|
(MemoryRelObject*)catalog->getMMObject(relObjectName);
|
|
if(!mmrel){
|
|
res->setPointer(0);
|
|
return 0;
|
|
}
|
|
MemoryAVLObject* obj = createAVLTree(mmrel, attrPos,
|
|
nl->Second(qp->GetType(s)));
|
|
res->setPointer(obj);
|
|
obj->deleteIfAllowed();
|
|
return 0;
|
|
|
|
} //end mcreateAVLtreeValMap
|
|
|
|
int mcreateAVLtreeVMMP (Word* args, Word& result,
|
|
int message, Word& local, Supplier s) {
|
|
|
|
MPointer* arg1 = (MPointer*)(args[0].addr);
|
|
result = qp->ResultStorage(s);
|
|
MPointer* res = (MPointer*) result.addr;
|
|
MemoryRelObject* mmrel = (MemoryRelObject*) arg1->GetValue();
|
|
ListExpr attrPos = ((CcInt*)args[2].addr)->GetValue();
|
|
if(!mmrel){
|
|
res->setPointer(0);
|
|
return 0;
|
|
}
|
|
MemoryAVLObject* obj = createAVLTree(mmrel, attrPos,
|
|
nl->Second(qp->GetType(s)));
|
|
res->setPointer(obj);
|
|
obj->deleteIfAllowed();
|
|
return 0;
|
|
}
|
|
int mcreateAVLtreeVMStream (Word* args, Word& result,
|
|
int message, Word& local, Supplier s) {
|
|
|
|
result = qp->ResultStorage(s);
|
|
MPointer* res = (MPointer*) result.addr;
|
|
|
|
int keyIndex = ((CcInt*) args[3].addr)->GetValue();
|
|
int tidIndex = ((CcInt*) args[4].addr)->GetValue();
|
|
|
|
Stream<Tuple> stream(args[0]);
|
|
Tuple* tuple;
|
|
memAVLtree* tree = new memAVLtree();
|
|
|
|
stream.open();
|
|
size_t availableMem = catalog->getAvailableMemSize();
|
|
size_t usedMem = 0;
|
|
|
|
while((tuple=stream.request()) && (usedMem < availableMem)){
|
|
TupleIdentifier* tid = (TupleIdentifier*) tuple->GetAttribute(tidIndex);
|
|
if(tid->IsDefined()){
|
|
Attribute* key = tuple->GetAttribute(keyIndex);
|
|
key->bringToMemory();
|
|
AttrIdPair p(key, tid->GetTid());
|
|
usedMem += key->GetMemSize() + sizeof(size_t);
|
|
tree->insert(p);
|
|
}
|
|
tuple->DeleteIfAllowed();
|
|
}
|
|
stream.close();
|
|
if(usedMem > availableMem){
|
|
delete tree;
|
|
res->setPointer(0);
|
|
return 0;
|
|
}
|
|
MemoryAVLObject* mo = new MemoryAVLObject(tree, usedMem,
|
|
nl->ToString(nl->Second(qp->GetType(s))),
|
|
true, getDBname());
|
|
res->setPointer(mo);
|
|
mo->deleteIfAllowed();
|
|
return 0;
|
|
}
|
|
|
|
|
|
ValueMapping mcreateAVLtreeVM[] =
|
|
{
|
|
mcreateAVLtreeVMMem,
|
|
mcreateAVLtreeVMMP,
|
|
mcreateAVLtreeVMStream
|
|
};
|
|
|
|
int mcreateAVLtreeSelect(ListExpr args){
|
|
if(nl->HasLength(args,3)){
|
|
return 2;
|
|
}
|
|
return Mem::checkType(nl->First(args))?0:1;
|
|
}
|
|
|
|
/*
|
|
|
|
5.16.4 Description of operator ~mcreateAVLtree~
|
|
|
|
*/
|
|
|
|
OperatorSpec mcreateAVLtreeSpec(
|
|
" MREL x IDENT -> mpointer(mem(avltree)) "
|
|
"|| stream(tuple)) x IDENT x IDENT -> mpointer(mem(avltree))",
|
|
"_ mcreateAVLtree[_]",
|
|
"Creates an AVLtree over an attribute of a relation. "
|
|
"This relation may be represented as main memory relation "
|
|
" (mem or mpointer) or as a stream of tuples. "
|
|
" The second argument represents the attribute to index. "
|
|
" If the relation is represented as a tuple stream, a third "
|
|
" argument specifies the name of some TID attribute. ",
|
|
"query mStaedte mcreateAVLtree [SName]"
|
|
);
|
|
|
|
/*
|
|
|
|
5.16.5 Instance of operator ~mcreateAVLtree~
|
|
|
|
*/
|
|
|
|
Operator mcreateAVLtreeOp (
|
|
"mcreateAVLtree",
|
|
mcreateAVLtreeSpec.getStr(),
|
|
3,
|
|
mcreateAVLtreeVM,
|
|
mcreateAVLtreeSelect,
|
|
mcreateAVLtreeTypeMap
|
|
);
|
|
|
|
|
|
|
|
/*
|
|
5.17 Operator ~mexactmatch~
|
|
Uses the given MemoryAVLObject or MemoryTTreeObject (as first argument)
|
|
to find all tuples in the given MemoryRelObject (as second argument)
|
|
with the same key value
|
|
|
|
|
|
5.17.1 Type Mapping Functions of operator ~mexactmatch~
|
|
tree x rel x key -> stream(Tuple)
|
|
|
|
|
|
*/
|
|
ListExpr mexactmatchTM(ListExpr args) {
|
|
string err ="{MAVLTREE(V),MTTREE} x REL(T) x V expected ";
|
|
|
|
if(nl->ListLength(args)!=3){
|
|
return listutils::typeError("three arguments expected");
|
|
}
|
|
|
|
// process first argument
|
|
ListExpr a1 = nl->First(args);
|
|
if(MPointer::checkType(a1)){
|
|
a1 = nl->Second(a1);
|
|
}
|
|
if(!Mem::checkType(a1)){
|
|
return listutils::typeError("first arg is not a memory object");
|
|
}
|
|
a1 = nl->Second(a1);
|
|
|
|
ListExpr a2 = nl->Second(args);
|
|
if(MPointer::checkType(a2)){
|
|
a2 = nl->Second(a2);
|
|
}
|
|
if(!Mem::checkType(a2)){
|
|
return listutils::typeError("second argument is not a memory object");
|
|
}
|
|
a2 = nl->Second(a2);
|
|
|
|
bool avl = MemoryAVLObject::checkType(a1);
|
|
bool ttree = MemoryTTreeObject::checkType(a1);
|
|
|
|
if(!avl && !ttree){
|
|
return listutils::typeError("first arg is not an avl tree or a t tree");
|
|
}
|
|
|
|
if(!Relation::checkType(a2)){
|
|
return listutils::typeError("second arg is not a memory relation");
|
|
}
|
|
|
|
ListExpr a3 = nl->Third(args);
|
|
|
|
if(!nl->Equal(a3, nl->Second(a1))){
|
|
return listutils::typeError("type managed by tree and key type differ "
|
|
);
|
|
}
|
|
|
|
ListExpr res = nl->TwoElemList( listutils::basicSymbol<Stream<Tuple> >(),
|
|
nl->Second(a2));
|
|
|
|
return nl->ThreeElemList(nl->SymbolAtom(Symbols::APPEND()),
|
|
nl->OneElemList(
|
|
nl->BoolAtom(avl)),
|
|
res);
|
|
|
|
}
|
|
|
|
class avlOperLI{
|
|
public:
|
|
avlOperLI(
|
|
memAVLtree* _tree,
|
|
vector<Tuple*>* _relation,
|
|
Attribute* _attr1,
|
|
Attribute* _attr2,
|
|
bool _below)
|
|
:relation(_relation), avltree(_tree), attr1(_attr1), attr2(_attr2),
|
|
below(_below){
|
|
|
|
isAvl = true;
|
|
if(!below){
|
|
avlit = avltree->tail(AttrIdPair(attr1,0));
|
|
}
|
|
res = true;
|
|
}
|
|
|
|
avlOperLI(
|
|
memttree* _tree,
|
|
vector<Tuple*>* _relation,
|
|
Attribute* _attr1,
|
|
Attribute* _attr2,
|
|
bool _below)
|
|
:relation(_relation), ttree(_tree), attr1(_attr1), attr2(_attr2),
|
|
below(_below){
|
|
isAvl = false;
|
|
if(!_below){
|
|
tit = ttree->tail(AttrIdPair(attr1,0));
|
|
}
|
|
res = true;
|
|
}
|
|
|
|
|
|
~avlOperLI(){}
|
|
|
|
|
|
Tuple* next(){
|
|
assert(!below);
|
|
// T-Tree
|
|
if(!isAvl) {
|
|
while(!tit.end()) {
|
|
thit = *tit;
|
|
if ((thit.getAttr())->Compare(attr2) > 0){ // end reached
|
|
return 0;
|
|
}
|
|
Tuple* result = relation->at(thit.getTid()-1);
|
|
if(result){
|
|
result->IncReference();
|
|
result->SetTupleId(thit.getTid());
|
|
tit++;
|
|
return result;
|
|
} else {
|
|
tit++;
|
|
}
|
|
} // end of iterator reached
|
|
return 0;
|
|
} else { // avl tree
|
|
while(!avlit.onEnd()){
|
|
avlhit = avlit.Get();
|
|
if ((avlhit->getAttr())->Compare(attr2) > 0){ // end reached
|
|
return 0;
|
|
}
|
|
|
|
Tuple* result = relation->at(avlhit->getTid()-1);
|
|
if(result){ // tuple exist
|
|
result->IncReference();
|
|
avlit.Next();
|
|
result->SetTupleId(avlhit->getTid());
|
|
return result;
|
|
} else { // tuple deleted
|
|
avlit.Next();
|
|
}
|
|
}
|
|
return 0; // end of iterator reached
|
|
}
|
|
return 0; // should never be reached
|
|
}
|
|
|
|
|
|
Tuple* matchbelow(){
|
|
assert(below);
|
|
if (res) {
|
|
// AVL-Tree
|
|
if(isAvl) {
|
|
size_t i = relation->size();
|
|
avlhit = avltree->GetNearestSmallerOrEqual
|
|
(AttrIdPair(attr1,i));
|
|
if (avlhit==0) {
|
|
return 0;
|
|
}
|
|
Tuple* result = relation->at(avlhit->getTid()-1);
|
|
if(result){ // present in index, but deleted in rel
|
|
result->IncReference();
|
|
result->SetTupleId(avlhit->getTid());
|
|
}
|
|
res = false;
|
|
return result;
|
|
} else { // ttree
|
|
size_t i = relation->size();
|
|
AttrIdPair s(attr1,i);
|
|
const AttrIdPair* t = ttree->GetNearestSmallerOrEqual(s, 0);
|
|
if(!t){
|
|
return 0;
|
|
}
|
|
Tuple* result = relation->at(t->getTid()-1);
|
|
if(result){
|
|
result->IncReference();
|
|
result->SetTupleId(t->getTid());
|
|
}
|
|
res = false;
|
|
return result;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
private:
|
|
vector<Tuple*>* relation;
|
|
memAVLtree* avltree;
|
|
memttree* ttree;
|
|
Attribute* attr1;
|
|
Attribute* attr2;
|
|
string keyType;
|
|
bool below;
|
|
avlIterator avlit;
|
|
ttree::Iterator<AttrIdPair,AttrComp> tit;
|
|
const AttrIdPair* avlhit;
|
|
AttrIdPair thit;
|
|
bool res;
|
|
bool isAvl;
|
|
};
|
|
|
|
|
|
/*
|
|
|
|
5.17.3 The Value Mapping Functions of operator ~mexactmatch~
|
|
|
|
*/
|
|
|
|
template<class T, class R, bool below>
|
|
int mexactmatchVMT (Word* args, Word& result,
|
|
int message, Word& local, Supplier s) {
|
|
|
|
avlOperLI* li = (avlOperLI*) local.addr;
|
|
|
|
|
|
switch (message)
|
|
{
|
|
case INIT: { // arguments required, create once in open
|
|
return 0;
|
|
}
|
|
case FINISH : {
|
|
qp->GetLocal2(s).addr = 0; // do not delete here
|
|
return 0;
|
|
}
|
|
|
|
case OPEN: {
|
|
if(li){
|
|
delete li;
|
|
local.addr=0;
|
|
}
|
|
MemoryRelObject* mro = (MemoryRelObject*) qp->GetLocal2(s).addr;
|
|
if(!mro){ // retrieve relation only once
|
|
R* relN = (R*) args[1].addr;
|
|
mro = getMemRel(relN, nl->Second(qp->GetType(s)));
|
|
qp->GetLocal2(s).addr = mro;
|
|
}
|
|
if(!mro){
|
|
return 0;
|
|
}
|
|
|
|
Attribute* key = (Attribute*) args[2].addr;
|
|
|
|
bool avl = ((CcBool*) args[3].addr)->GetValue();
|
|
|
|
T* treeN = (T*) args[0].addr;
|
|
//ListExpr subtype = qp->GetType(qp->GetSon(s,2));
|
|
|
|
|
|
if(avl) {
|
|
memAVLtree* avltree = getAVLtree(treeN);
|
|
local.addr= new avlOperLI(avltree,
|
|
mro->getmmrel(),
|
|
key,key,
|
|
below);
|
|
} else {
|
|
MemoryTTreeObject* ttree = getTtree(treeN);
|
|
if(ttree) {
|
|
local.addr= new avlOperLI(ttree->gettree(),
|
|
mro->getmmrel(),
|
|
key,key,
|
|
below);
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
case REQUEST:
|
|
if(below){
|
|
result.addr=li?li->matchbelow():0;
|
|
} else {
|
|
result.addr=li?li->next():0;
|
|
}
|
|
return result.addr?YIELD:CANCEL;
|
|
|
|
case CLOSE:
|
|
if(li) {
|
|
delete li;
|
|
local.addr = 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
ValueMapping mexactmatchVM[] = {
|
|
mexactmatchVMT<Mem, Mem, false>,
|
|
mexactmatchVMT<Mem, MPointer, false>,
|
|
mexactmatchVMT<MPointer, Mem, false>,
|
|
mexactmatchVMT<MPointer, MPointer, false>,
|
|
};
|
|
|
|
ValueMapping matchbelowVM[] = {
|
|
mexactmatchVMT<Mem, Mem, true>,
|
|
mexactmatchVMT<Mem, MPointer, true>,
|
|
mexactmatchVMT<MPointer, Mem, true>,
|
|
mexactmatchVMT<MPointer, MPointer, true>,
|
|
};
|
|
|
|
int mexactmatchSelect(ListExpr args){
|
|
int n1 = Mem::checkType(nl->First(args))?0:2;
|
|
int n2 = Mem::checkType(nl->Second(args))?0:1;
|
|
return n1 + n2;
|
|
}
|
|
|
|
/*
|
|
|
|
5.17.4 Description of operator ~mexactmatch~
|
|
|
|
*/
|
|
|
|
OperatorSpec mexactmatchSpec(
|
|
"MTREE x MREL x T -> stream(Tuple), MTREE is an avltree or ttree, "
|
|
"MTREE, MRel represented as string, mem, or mpointer",
|
|
"_ _ mexactmatch[_]",
|
|
"Uses the given MemoryAVLObject (as first argument) to find all tuples "
|
|
"in the given MemoryRelObject (as second argument) "
|
|
"that have the same attribute value",
|
|
"query mStaedte_SName, mStaedte mexactmatch [\"Dortmund\"] count"
|
|
);
|
|
|
|
/*
|
|
|
|
5.17.5 Instance of operator ~mexactmatch~
|
|
|
|
*/
|
|
Operator mexactmatchOp (
|
|
"mexactmatch",
|
|
mexactmatchSpec.getStr(),
|
|
9,
|
|
mexactmatchVM,
|
|
mexactmatchSelect,
|
|
mexactmatchTM
|
|
);
|
|
|
|
|
|
/*
|
|
|
|
5.19.4 Description of operator ~matchbelow~
|
|
|
|
*/
|
|
|
|
OperatorSpec matchbelowSpec(
|
|
" MTREE x MREL x T -> stream(tuple(X)), MTREE is an avl-tree or an ttree, "
|
|
"MTree, MRel represented as string, mem, or mpointer",
|
|
"_ _ matchbelow[_]",
|
|
"returns for a key (third argument) the tuple which "
|
|
" contains the biggest attribute value in the AVLtree (first argument) "
|
|
" which is smaller than key or equal to key",
|
|
"query mStaedte_SNamem mStaedte matchbelow [\"Dortmund\"] count"
|
|
);
|
|
|
|
Operator matchbelowOp (
|
|
"matchbelow",
|
|
matchbelowSpec.getStr(),
|
|
9,
|
|
matchbelowVM,
|
|
mexactmatchSelect,
|
|
mexactmatchTM
|
|
);
|
|
|
|
|
|
/*
|
|
5.18 Operator ~mrange~
|
|
Uses the given MemoryAVLObject or MemoryTTreeObject (as first argument)
|
|
to find all tuples in the given MemoryRelObject (as second argument)
|
|
which are between the first and the second attribute value
|
|
(as third and fourth argument)
|
|
|
|
5.18.1 Type Mapping Functions of operator ~mrange~
|
|
MAVLTREE(V) x MREL(T) x key x key -> stream(T)
|
|
|
|
|
|
*/
|
|
ListExpr mrangeTypeMap(ListExpr args)
|
|
{
|
|
if(nl->ListLength(args)!=4){
|
|
return listutils::typeError("four arguments expected");
|
|
}
|
|
ListExpr a1 = nl->First(args);
|
|
ListExpr a2 = nl->Second(args);
|
|
ListExpr a3 = nl->Third(args);
|
|
ListExpr a4 = nl->Fourth(args);
|
|
|
|
if(MPointer::checkType(a1)){
|
|
a1 = nl->Second(a1);
|
|
}
|
|
if(!Mem::checkType(a1)){
|
|
return listutils::typeError("first argument is not a memory object");
|
|
}
|
|
if(MPointer::checkType(a2)){
|
|
a2 = nl->Second(a2);
|
|
}
|
|
if(!Mem::checkType(a2)){
|
|
return listutils::typeError("second argument is not a memory object");
|
|
}
|
|
|
|
|
|
a1 = nl->Second(a1); // remove mem
|
|
a2 = nl->Second(a2);
|
|
|
|
if(!MemoryAVLObject::checkType(a1) && !MemoryTTreeObject::checkType(a1)){
|
|
return listutils::typeError( "(first arg is not an avl tree or a ttree)");
|
|
}
|
|
|
|
if(!Relation::checkType(a2)){
|
|
return listutils::typeError(" (second arg is not a memory relation)");
|
|
}
|
|
|
|
ListExpr treeType = nl->Second(a1);
|
|
if(!nl->Equal(treeType, a3)){
|
|
return listutils::typeError("treetype and type of arg 3 differ");
|
|
}
|
|
if(!nl->Equal(treeType, a4)){
|
|
return listutils::typeError("treetype and type of arg 4 differ");
|
|
}
|
|
return nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()),
|
|
nl->Second(a2));
|
|
}
|
|
|
|
/*
|
|
|
|
5.18.3 The Value Mapping Functions of operator ~mrange~
|
|
|
|
*/
|
|
|
|
template<class T, class R, bool isAVL>
|
|
int mrangeVMT (Word* args, Word& result,
|
|
int message, Word& local, Supplier s) {
|
|
|
|
avlOperLI* li = (avlOperLI*) local.addr;
|
|
|
|
switch (message)
|
|
{
|
|
case OPEN: {
|
|
if(li){
|
|
delete li;
|
|
local.addr=0;
|
|
}
|
|
|
|
R* relN = (R*) args[1].addr;
|
|
MemoryRelObject* mro;
|
|
if(R::requiresTypeCheckInVM()){
|
|
mro = getMemRel(relN, nl->Second(qp->GetType(s)));
|
|
} else {
|
|
mro = getMemRel(relN);
|
|
}
|
|
if(!mro){
|
|
return 0;
|
|
}
|
|
Attribute* key1 = (Attribute*) args[2].addr;
|
|
Attribute* key2 = (Attribute*) args[3].addr;
|
|
T* treeN = (T*) args[0].addr;
|
|
|
|
if(isAVL) {
|
|
memAVLtree* avltree;
|
|
if(T::requiresTypeCheckInVM()){
|
|
ListExpr subtype = qp->GetType(qp->GetSon(s,2));
|
|
avltree = getAVLtree(treeN, subtype);
|
|
} else {
|
|
avltree = getAVLtree(treeN);
|
|
}
|
|
local.addr= new avlOperLI(avltree,
|
|
mro->getmmrel(),
|
|
key1,key2,
|
|
false);
|
|
} else {
|
|
MemoryTTreeObject* ttree;
|
|
if(T::requiresTypeCheckInVM()){
|
|
//ListExpr subtype = qp->GetType(qp->GetSon(s,2));
|
|
ttree = getTtree(treeN); //, subtype);
|
|
} else {
|
|
ttree = getTtree(treeN);
|
|
}
|
|
if(ttree) {
|
|
local.addr= new avlOperLI(ttree->gettree(),
|
|
mro->getmmrel(),
|
|
key1,key2,
|
|
false);
|
|
}
|
|
}
|
|
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;
|
|
}
|
|
|
|
|
|
|
|
|
|
ValueMapping mrangeVM[] = {
|
|
mrangeVMT<Mem,Mem,true>,
|
|
mrangeVMT<Mem,Mem,false>,
|
|
mrangeVMT<Mem,MPointer,true>,
|
|
mrangeVMT<Mem,MPointer,false>,
|
|
mrangeVMT<MPointer,Mem, true>,
|
|
mrangeVMT<MPointer,Mem, false>,
|
|
mrangeVMT<MPointer,MPointer,true>,
|
|
mrangeVMT<MPointer,MPointer,false>
|
|
};
|
|
|
|
int mrangeSelect(ListExpr args){
|
|
int n1 = 0;
|
|
ListExpr a1 = nl->First(args);
|
|
if(MPointer::checkType(a1)){
|
|
n1 = 4;
|
|
a1 = nl->Second(a1);
|
|
}
|
|
ListExpr tt = nl->Second(a1);
|
|
int n3 = MemoryAVLObject::checkType(tt)?0:1;
|
|
ListExpr a2 = nl->Second(args);
|
|
int n2 = MPointer::checkType(a2)?2:0;
|
|
return n1+n2+n3;
|
|
}
|
|
|
|
/*
|
|
|
|
5.18.4 Description of operator ~mrange~
|
|
|
|
*/
|
|
|
|
OperatorSpec mrangeSpec(
|
|
"MTREE x MREL x T x T -> stream(Tuple(X)), MTREE is an avl-tree "
|
|
"or a t-tree, MTREE, MREL represented as mem or mpointer ",
|
|
"_ _ mrange[_,_]",
|
|
"Uses the given avl-tree or a ttree to find all tuples"
|
|
" in the given relation which are between "
|
|
"the first and the second attribute value.",
|
|
"query Staedte_SName Staedte mrange [\"Aachen\",\"Dortmund\"] count"
|
|
);
|
|
|
|
/*
|
|
|
|
5.18.5 Instance of operator ~mrange~
|
|
|
|
*/
|
|
Operator mrangeOp (
|
|
"mrange",
|
|
mrangeSpec.getStr(),
|
|
8,
|
|
mrangeVM,
|
|
mrangeSelect,
|
|
mrangeTypeMap
|
|
);
|
|
|
|
|
|
|
|
/*
|
|
Operators providing a tid-stream
|
|
|
|
mexactzmatchS
|
|
mrangeS
|
|
matchbelowS
|
|
|
|
*/
|
|
template<bool wrap>
|
|
ListExpr mexactmatchSTM(ListExpr args){
|
|
string err =" MTREE(T) x T expected";
|
|
if(!nl->HasLength(args,2)){
|
|
return listutils::typeError(err + " (wrong number of args)");
|
|
}
|
|
ListExpr a1 = nl->TheEmptyList();
|
|
if(!getMemSubType(nl->First(args),a1)){
|
|
return listutils::typeError("first arg is not a memory object");
|
|
}
|
|
if(!MemoryAVLObject::checkType(a1)){
|
|
return listutils::typeError(err + " (1st arg i not an avl tree)");
|
|
}
|
|
if(!nl->Equal(nl->Second(a1), nl->Second(args))){
|
|
return listutils::typeError("avl type and search type differ");
|
|
}
|
|
if(!wrap){
|
|
return nl->TwoElemList(
|
|
listutils::basicSymbol<Stream<TupleIdentifier> >(),
|
|
listutils::basicSymbol<TupleIdentifier>());
|
|
} else {
|
|
ListExpr attrList = nl->OneElemList(
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom("TID"),
|
|
listutils::basicSymbol<TupleIdentifier>()));
|
|
return nl->TwoElemList(
|
|
listutils::basicSymbol<Stream<Tuple> >(),
|
|
nl->TwoElemList(
|
|
listutils::basicSymbol<Tuple>(),
|
|
attrList));
|
|
}
|
|
}
|
|
|
|
|
|
template<bool wrap>
|
|
ListExpr mrangeSTM(ListExpr args){
|
|
string err =" MAVLTREE(T) x T x T expected";
|
|
if(!nl->HasLength(args,3)){
|
|
return listutils::typeError(err + " (wrong number of args)");
|
|
}
|
|
string errMsg;
|
|
ListExpr a1;
|
|
if(!getMemSubType(nl->First(args),a1)){
|
|
return listutils::typeError("first arg is not a memory object");
|
|
}
|
|
if(!MemoryAVLObject::checkType(a1)){
|
|
return listutils::typeError(err + " (1st arg i not an avl tree)");
|
|
}
|
|
if(!nl->Equal(nl->Second(a1), nl->Second(args))){
|
|
return listutils::typeError("avl type and search type 1 differ");
|
|
}
|
|
if(!nl->Equal(nl->Second(a1), nl->Third(args))){
|
|
return listutils::typeError("avl type and search type 2 differ");
|
|
}
|
|
if(!wrap){
|
|
return nl->TwoElemList(
|
|
listutils::basicSymbol<Stream<TupleIdentifier> >(),
|
|
listutils::basicSymbol<TupleIdentifier>());
|
|
} else {
|
|
ListExpr attrList = nl->OneElemList(
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom("TID"),
|
|
listutils::basicSymbol<TupleIdentifier>()));
|
|
return nl->TwoElemList(
|
|
listutils::basicSymbol<Stream<Tuple> >(),
|
|
nl->TwoElemList(
|
|
listutils::basicSymbol<Tuple>(),
|
|
attrList));
|
|
}
|
|
}
|
|
|
|
class AVLOpS{
|
|
public:
|
|
AVLOpS(memAVLtree* _tree,
|
|
Attribute* _beg, Attribute* _end):
|
|
tree(_tree), end(_end){
|
|
it = tree->tail(AttrIdPair(_beg,0));
|
|
tt = 0;
|
|
}
|
|
|
|
AVLOpS(memAVLtree* _tree,
|
|
Attribute* _beg,
|
|
Attribute* _end,
|
|
ListExpr tupleType):
|
|
tree(_tree), end(_end){
|
|
it = tree->tail(AttrIdPair(_beg,0));
|
|
tt = new TupleType(tupleType);
|
|
}
|
|
|
|
~AVLOpS(){
|
|
if(tt){
|
|
tt->DeleteIfAllowed();
|
|
}
|
|
}
|
|
|
|
|
|
TupleIdentifier* nextTID(){
|
|
if(it.onEnd()){
|
|
return 0;
|
|
}
|
|
const AttrIdPair* p = *it;
|
|
it++;
|
|
int cmp = p->getAttr()->Compare(end);
|
|
if(cmp>0){
|
|
return 0;
|
|
}
|
|
return new TupleIdentifier(true,p->getTid());
|
|
}
|
|
|
|
Tuple* nextTuple(){
|
|
assert(tt);
|
|
TupleIdentifier* tid = nextTID();
|
|
if(!tid){
|
|
return 0;
|
|
}
|
|
Tuple* res = new Tuple(tt);
|
|
res->PutAttribute(0,tid);
|
|
return res;
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
memAVLtree* tree;
|
|
Attribute* end;
|
|
avlIterator it;
|
|
TupleType* tt;
|
|
};
|
|
|
|
|
|
template<class T, bool wrap>
|
|
int mrangeSVMT (Word* args, Word& result,
|
|
int message, Word& local, Supplier s) {
|
|
|
|
|
|
AVLOpS* li = (AVLOpS*) local.addr;
|
|
switch(message){
|
|
case OPEN:{
|
|
if(li){
|
|
delete li;
|
|
local.addr = 0;
|
|
}
|
|
T* treeN = (T*) args[0].addr;
|
|
memAVLtree* tree = getAVLtree(treeN, qp->GetType(qp->GetSon(s,1)));
|
|
if(!tree){
|
|
return 0;
|
|
}
|
|
Attribute* beg = (Attribute*) args[1].addr;
|
|
Attribute* end = (Attribute*) args[qp->GetNoSons(s)-1].addr;
|
|
if(!wrap){
|
|
local.addr = new AVLOpS(tree,beg,end);
|
|
} else {
|
|
local.addr = new AVLOpS(tree,beg,end,
|
|
nl->Second(GetTupleResultType(s)));
|
|
}
|
|
return 0;
|
|
}
|
|
case REQUEST: {
|
|
if(!li){
|
|
result.addr = 0;
|
|
} else {
|
|
if(wrap){
|
|
result.addr = li->nextTuple();
|
|
} else {
|
|
result.addr = li->nextTID();
|
|
}
|
|
}
|
|
return result.addr?YIELD:CANCEL;
|
|
}
|
|
|
|
case CLOSE:{
|
|
if(li){
|
|
delete li;
|
|
local.addr = 0;
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
ValueMapping mrangeSVM[] = {
|
|
mrangeSVMT<Mem, true>,
|
|
mrangeSVMT<MPointer, true>
|
|
};
|
|
|
|
int mrangeSSelect(ListExpr args){
|
|
ListExpr a1 = nl->First(args);
|
|
if(Mem::checkType(a1)) return 0;
|
|
if(MPointer::checkType(a1)) return 1;
|
|
return -1;
|
|
}
|
|
|
|
|
|
OperatorSpec mexactmatchSSpec(
|
|
"MTREE x MREL x T -> stream(tuple((TID tid))), MTREE is an avl-tree "
|
|
"or a t-tree, MTREE, MREL represented as string, mem, or mpointer ",
|
|
"_ memexactmatchS[_]",
|
|
"Retrieves the tuple ids from an avl-tree whose "
|
|
"keys have the value given by the second arg.",
|
|
"query mstrassen_Name mexactmatch[\"Hirzerweg\"] count"
|
|
);
|
|
|
|
OperatorSpec mrangeSSpec(
|
|
"MTREE x T x T -> stream(tuple((TID tid))), MTREE is an avl-tree "
|
|
" represented as mem or mpointer",
|
|
"_ mrangeS[_,_] ",
|
|
"Retrieves the tuple ids from an avl-tree whose key "
|
|
"is within the range defined by the last two arguments.",
|
|
"query mstrassen_Name mrangeS[\"A\",\"B\"] count"
|
|
);
|
|
|
|
|
|
|
|
Operator mexactmatchSOp(
|
|
"mexactmatchS",
|
|
mexactmatchSSpec.getStr(),
|
|
2,
|
|
mrangeSVM,
|
|
mrangeSSelect,
|
|
mexactmatchSTM<true>
|
|
);
|
|
|
|
Operator mrangeSOp(
|
|
"mrangeS",
|
|
mrangeSSpec.getStr(),
|
|
2,
|
|
mrangeSVM,
|
|
mrangeSSelect,
|
|
mrangeSTM<true>
|
|
);
|
|
|
|
template<bool wrap>
|
|
ListExpr matchbelowSTM(ListExpr args){
|
|
string err =" (mem (avl T)) x T expected";
|
|
if(!nl->HasLength(args,2)){
|
|
return listutils::typeError(err + " (wrong number of args)");
|
|
}
|
|
ListExpr a1;
|
|
if(!getMemSubType(nl->First(args),a1)){
|
|
return listutils::typeError("1st arg is not a memory object");
|
|
}
|
|
if(!MemoryAVLObject::checkType(a1)){
|
|
return listutils::typeError(err + " (1st arg i not an avl tree)");
|
|
}
|
|
if(!nl->Equal(nl->Second(a1), nl->Second(args))){
|
|
return listutils::typeError("avl type and search type differ");
|
|
}
|
|
if(!wrap){
|
|
return nl->TwoElemList(
|
|
listutils::basicSymbol<Stream<TupleIdentifier> >(),
|
|
listutils::basicSymbol<TupleIdentifier>());
|
|
} else {
|
|
ListExpr attrList = nl->OneElemList(
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom("TID"),
|
|
listutils::basicSymbol<TupleIdentifier>()));
|
|
return nl->TwoElemList(
|
|
listutils::basicSymbol<Stream<Tuple> >(),
|
|
nl->TwoElemList(
|
|
listutils::basicSymbol<Tuple>(),
|
|
attrList));
|
|
}
|
|
}
|
|
|
|
|
|
template<class T, bool wrap>
|
|
int matchbelowSVMT (Word* args, Word& result,
|
|
int message, Word& local, Supplier s) {
|
|
|
|
switch (message){
|
|
case OPEN: {
|
|
if(local.addr){
|
|
if(wrap){
|
|
((Tuple*)local.addr)->DeleteIfAllowed();
|
|
} else {
|
|
((TupleIdentifier*)local.addr)->DeleteIfAllowed();
|
|
}
|
|
local.addr=0;
|
|
}
|
|
T* treeN = (T*) args[0].addr;
|
|
memAVLtree* tree = getAVLtree(treeN, qp->GetType(qp->GetSon(s,1)));
|
|
if(!tree){
|
|
return 0;
|
|
}
|
|
Attribute* attr = (Attribute*) args[1].addr;
|
|
AttrIdPair searchP(attr, numeric_limits<size_t>::max());
|
|
const AttrIdPair* p = tree->GetNearestSmallerOrEqual(searchP);
|
|
if(p){
|
|
TupleIdentifier* tid = new TupleIdentifier(true,p->getTid());
|
|
if(wrap){
|
|
TupleType* tt = new TupleType(nl->Second(
|
|
GetTupleResultType(s)));
|
|
Tuple* res = new Tuple(tt);
|
|
res->PutAttribute(0,tid);
|
|
local.addr = res;
|
|
tt->DeleteIfAllowed();
|
|
} else {
|
|
local.addr = tid;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
case REQUEST : {
|
|
result.addr = local.addr;
|
|
local.addr = 0;
|
|
return result.addr?YIELD:CANCEL;
|
|
}
|
|
case CLOSE :{
|
|
if(local.addr){
|
|
if(wrap){
|
|
((Tuple*)local.addr)->DeleteIfAllowed();
|
|
} else {
|
|
((TupleIdentifier*)local.addr)->DeleteIfAllowed();
|
|
}
|
|
local.addr=0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
ValueMapping matchbelowSVM[] = {
|
|
matchbelowSVMT<Mem, true>,
|
|
matchbelowSVMT<MPointer, true>
|
|
};
|
|
|
|
int matchbelowSSelect(ListExpr args){
|
|
ListExpr a1 = nl->First(args);
|
|
if(Mem::checkType(a1)) return 0;
|
|
if(MPointer::checkType(a1)) return 1;
|
|
return -1;
|
|
}
|
|
|
|
OperatorSpec matchbelowSSpec(
|
|
"MTREE x T -> stream(tuple((TID tid))) , where MTREE in an avl-tree "
|
|
" represented as mem or as an mpointer ",
|
|
"_ matchbelowS[_]",
|
|
"Returns the tid of the entry in the avl tree whose key "
|
|
"is smaller or equal to the key attribute. If the given "
|
|
"key is smaller than all stored values, the resulting stream "
|
|
"will be empty.",
|
|
"query mstrassen_Name matchbelowS[\"B\"] count"
|
|
);
|
|
|
|
Operator matchbelowSOp(
|
|
"matchbelowS",
|
|
matchbelowSSpec.getStr(),
|
|
2,
|
|
matchbelowSVM,
|
|
matchbelowSSelect,
|
|
matchbelowSTM<true>
|
|
);
|
|
|
|
|
|
/*
|
|
6 M-tree support
|
|
|
|
6.1 template class that enables the use of Flob types in an M-tree
|
|
|
|
*/
|
|
|
|
/*
|
|
6.1 ~mcreatemtree~: Creation of an M-tree
|
|
|
|
6.1.1 Type Mapping
|
|
|
|
We support two variants. The first variant gets a tuple stream,
|
|
the name of the attribute to index and the attribute name of a
|
|
tid attribute. The second gets a main memory relation and the
|
|
attribute that should be indexed.
|
|
|
|
*/
|
|
|
|
|
|
ListExpr mcreatemtreeTM(ListExpr args){
|
|
string err="expected: stream(tuple) x attrname x attrname [x geoid]"
|
|
" or MREL x attrname [x geoid]";
|
|
|
|
// ensure at least 2 arguments
|
|
if(!nl->HasMinLength(args,2)){
|
|
return listutils::typeError(err+" (less than 2 arguments)");
|
|
}
|
|
bool isTS = Stream<Tuple>::checkType(nl->First(args));
|
|
bool isMP = MPointer::checkType(nl->First(args));
|
|
if(!isTS && !isMP) {
|
|
return listutils::typeError(err + " (first arg is not a tuple stream "
|
|
"and not an mpointer)");
|
|
}
|
|
if(nl->AtomType(nl->Second(args)) != SymbolType){
|
|
return listutils::typeError(err + " (second argument is not a valid "
|
|
"attribute name)");
|
|
}
|
|
bool geoidPresent = false;
|
|
if(isTS){
|
|
if(!nl->HasLength(args,3) && !nl->HasLength(args,4)){
|
|
return listutils::typeError("for a tuplestream, "
|
|
"3 or 4 arguments are required");
|
|
}
|
|
if(nl->AtomType(nl->Third(args)) != SymbolType){
|
|
return listutils::typeError(err + " (third argument is not a valid "
|
|
"attribute name)");
|
|
}
|
|
if(nl->HasLength(args,4)){
|
|
if(!Geoid::checkType(nl->Fourth(args))){
|
|
return listutils::typeError("fourth argument is not a geoid");
|
|
}
|
|
geoidPresent = true;
|
|
}
|
|
}
|
|
else {
|
|
if(!nl->HasLength(args,2) && !nl->HasLength(args,3)){
|
|
return listutils::typeError("for an mpointer, 2 or 3 "
|
|
" arguments are required");
|
|
}
|
|
if(nl->HasLength(args,3)){
|
|
if(!Geoid::checkType(nl->Third(args))){
|
|
return listutils::typeError("last argument is not an geoid");
|
|
}
|
|
geoidPresent = true;
|
|
}
|
|
}
|
|
|
|
// extract tuple type from first argument
|
|
ListExpr tupletype;
|
|
if(isMP){
|
|
ListExpr mpt = nl->Second(nl->Second(nl->First(args)));
|
|
if(!Relation::checkType(mpt)){
|
|
return listutils::typeError("mpointer to a non-relation");
|
|
}
|
|
tupletype = nl->Second(mpt);
|
|
} else {
|
|
tupletype = nl->Second(nl->First(args));
|
|
}
|
|
|
|
ListExpr attrList =nl->Second(tupletype);
|
|
|
|
string name = nl->SymbolValue(nl->Second(args));
|
|
ListExpr type;
|
|
int index1 = listutils::findAttribute(attrList, name, type);
|
|
if(!index1){
|
|
return listutils::typeError("attribute " + name
|
|
+ " not part of the tuple");
|
|
}
|
|
// support geoid only for point, mpoint, cupoint, cmpoint
|
|
if(geoidPresent){
|
|
if(!Point::checkType(type) && !temporalalgebra::MPoint::checkType(type) &&
|
|
!temporalalgebra::CUPoint::checkType(type) &&
|
|
!temporalalgebra::CMPoint::checkType(type)) {
|
|
return listutils::typeError("geoid support only for (m|cu|cm|eps)point");
|
|
}
|
|
}
|
|
|
|
|
|
int index2 = -1;
|
|
if(isTS){
|
|
string tidname = nl->SymbolValue(nl->Third(args));
|
|
ListExpr tidtype;
|
|
index2 = listutils::findAttribute(attrList, tidname, tidtype);
|
|
if(!index2){
|
|
return listutils::typeError("attribute " + tidname
|
|
+ "not known in tuple");
|
|
}
|
|
if(!TupleIdentifier::checkType(tidtype)){
|
|
return listutils::typeError("attribute " + tidname
|
|
+ " not of type tid");
|
|
}
|
|
}
|
|
|
|
// check for supported type, extend if required
|
|
int no = mtreehelper::getTypeNo(type,12);
|
|
if(no <0){
|
|
return listutils::typeError("there is no known distance function for type "
|
|
+ nl->ToString(type));
|
|
}
|
|
|
|
ListExpr resType = MPointer::wrapType(
|
|
Mem::wrapType(
|
|
nl->TwoElemList(
|
|
listutils::basicSymbol<
|
|
MemoryMtreeObject<Point,
|
|
StdDistComp<Point> > >(),
|
|
type
|
|
)));
|
|
ListExpr appendList;
|
|
if(isTS){
|
|
if(geoidPresent){
|
|
appendList = nl->ThreeElemList(
|
|
nl->IntAtom(index1-1),
|
|
nl->IntAtom(index2-1),
|
|
nl->StringAtom(nl->ToString(type)));
|
|
} else {
|
|
appendList = nl->FourElemList(
|
|
nl->TwoElemList(listutils::basicSymbol<Geoid>(),
|
|
listutils::getUndefined()),
|
|
nl->IntAtom(index1-1),
|
|
nl->IntAtom(index2-1),
|
|
nl->StringAtom(nl->ToString(type)));
|
|
|
|
}
|
|
} else {
|
|
if(geoidPresent){
|
|
appendList = nl->TwoElemList( nl->IntAtom(index1-1),
|
|
nl->StringAtom(nl->ToString(type)));
|
|
} else {
|
|
appendList = nl->ThreeElemList(
|
|
nl->TwoElemList(listutils::basicSymbol<Geoid>(),
|
|
listutils::getUndefined()),
|
|
nl->IntAtom(index1-1),
|
|
nl->StringAtom(nl->ToString(type)));
|
|
}
|
|
}
|
|
|
|
ListExpr result = nl->ThreeElemList(
|
|
nl->SymbolAtom(Symbols::APPEND()),
|
|
appendList,
|
|
resType);
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
6.2 Value Mapping template
|
|
|
|
*/
|
|
template <class T>
|
|
int mcreatemtreeVMTStream (Word* args, Word& result, int message,
|
|
Word& local, Supplier s) {
|
|
|
|
result = qp->ResultStorage(s);
|
|
MPointer* res = (MPointer*) result.addr;
|
|
Geoid* geoid = (Geoid*) args[3].addr;
|
|
int index1 = ((CcInt*) args[4].addr)->GetValue();
|
|
int index2 = ((CcInt*) args[5].addr)->GetValue();
|
|
|
|
if(!geoid->IsDefined()){
|
|
geoid = 0;
|
|
}
|
|
|
|
StdDistComp<T> dc(geoid);
|
|
MMMTree<MTreeEntry<T>, StdDistComp<T> >* tree =
|
|
new MMMTree<MTreeEntry<T>, StdDistComp<T> >(4, 8, dc);
|
|
// typedef pair<T,TupleId> treeentry_t;
|
|
// MMMTree<treeentry_t,StdDistComp<T>,MemCloner<treeentry_t> >* tree =
|
|
// new MMMTree<treeentry_t,StdDistComp<T>,
|
|
// MemCloner<treeentry_t>>(4,8,dc);
|
|
|
|
Stream<Tuple> stream(args[0]);
|
|
stream.open();
|
|
Tuple* tuple;
|
|
bool flobused = false;
|
|
while( (tuple = stream.request())){
|
|
T* attr = (T*) tuple->GetAttribute(index1);
|
|
TupleIdentifier* tid = (TupleIdentifier*) tuple->GetAttribute(index2);
|
|
if(tid->IsDefined()){
|
|
// T copy = *attr;
|
|
flobused = flobused || (attr->NumOfFLOBs()>0);
|
|
MTreeEntry<T> entry(*attr, tid->GetTid());
|
|
// pair<T,TupleId> p(copy, tid->GetTid());
|
|
tree->insert(entry);
|
|
}
|
|
tuple->DeleteIfAllowed();
|
|
}
|
|
stream.close();
|
|
size_t usedMem = tree->memSize();
|
|
ListExpr typeList = nl->Second(qp->GetType(s));
|
|
MemoryMtreeObject<T, StdDistComp<T> >* mtree =
|
|
new MemoryMtreeObject<T, StdDistComp<T> > (tree,
|
|
usedMem,
|
|
nl->ToString(typeList),
|
|
!flobused, getDBname());
|
|
// MemoryMtreeObject<T,StdDistComp<T> >* mtree =
|
|
// new MemoryMtreeObject<T, StdDistComp<T> > (tree,
|
|
// usedMem,
|
|
// nl->ToString(typeList),
|
|
// !flobused, getDBname());
|
|
mtreehelper::increaseCounter("counterMCreateMTree",
|
|
mtree->getmtree()->getDistComp().getNoDistFunCalls());
|
|
res->setPointer(mtree);
|
|
mtree->deleteIfAllowed();
|
|
return 0;
|
|
}
|
|
|
|
|
|
template <class T>
|
|
int mcreatemtreeVMTMP (Word* args, Word& result, int message,
|
|
Word& local, Supplier s) {
|
|
|
|
result = qp->ResultStorage(s);
|
|
MPointer* res = (MPointer*) result.addr;
|
|
MPointer* mrelp = (MPointer*) args[0].addr;
|
|
if(mrelp->isNull()){
|
|
res->setPointer(0);
|
|
return 0;
|
|
}
|
|
Geoid* geoid = (Geoid*) args[2].addr;
|
|
int index1 = ((CcInt*) args[3].addr)->GetValue();
|
|
string tn = ((CcString*) args[4].addr)->GetValue();
|
|
|
|
if(!geoid->IsDefined()){
|
|
geoid = 0;
|
|
}
|
|
|
|
MemoryRelObject* mrel = (MemoryRelObject*) mrelp->GetValue();
|
|
vector<Tuple*>* v = mrel->getmmrel();
|
|
|
|
|
|
StdDistComp<T> dc(geoid);
|
|
// typedef pair<T,TupleId> treeentry_t;
|
|
MMMTree<MTreeEntry<T>, StdDistComp<T> >* tree =
|
|
new MMMTree<MTreeEntry<T>, StdDistComp<T> >(4, 8, dc);
|
|
// MMMTree<treeentry_t,StdDistComp<T>,MemCloner<treeentry_t> >* tree =
|
|
// new MMMTree<treeentry_t,StdDistComp<T>,
|
|
// MemCloner<treeentry_t> >(4,8,dc);
|
|
|
|
Tuple* tuple;
|
|
bool flobused = false;
|
|
if(v){
|
|
for(size_t i=0;i<v->size();i++){
|
|
tuple = v->at(i);
|
|
if(tuple){
|
|
T* attr = (T*) tuple->GetAttribute(index1);
|
|
// T copy = *attr;
|
|
flobused = flobused || (attr->NumOfFLOBs()>0);
|
|
MTreeEntry<T> entry(*attr, i+1);
|
|
// pair<T,TupleId> p(copy, i+1);
|
|
tree->insert(entry);
|
|
entry.Destroy();
|
|
}
|
|
}
|
|
}
|
|
size_t usedMem = tree->memSize();
|
|
ListExpr typeList = nl->Second(qp->GetType(s));
|
|
MemoryMtreeObject<T, StdDistComp<T> >* mtree =
|
|
new MemoryMtreeObject<T, StdDistComp<T> > (tree,
|
|
usedMem,
|
|
nl->ToString(typeList),
|
|
!flobused, getDBname());
|
|
// MemoryMtreeObject<T,StdDistComp<T> >* mtree =
|
|
// new MemoryMtreeObject<T, StdDistComp<T> > (tree,
|
|
// usedMem,
|
|
// nl->ToString(typeList),
|
|
// !flobused, getDBname());
|
|
mtreehelper::increaseCounter("counterMCreateMTree",
|
|
mtree->getmtree()->getDistComp().getNoDistFunCalls());
|
|
res->setPointer(mtree);
|
|
mtree->deleteIfAllowed();
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
6.3 Selection and Value Mapping Array
|
|
|
|
*/
|
|
int mcreatemtreeSelect(ListExpr args){
|
|
int o1;
|
|
string attrName = nl->SymbolValue(nl->Second(args));
|
|
ListExpr attrList;
|
|
if(Stream<Tuple>::checkType(nl->First(args))){
|
|
o1 = 0;
|
|
attrList = nl->Second(nl->Second(nl->First(args)));
|
|
} else {
|
|
o1 = 12;
|
|
attrList=nl->Second(nl->Second(nl->Second(nl->Second(nl->First(args)))));
|
|
// mpointer mem rel tuple
|
|
}
|
|
|
|
ListExpr type;
|
|
listutils::findAttribute(attrList, attrName, type);
|
|
return o1 + mtreehelper::getTypeNo(type,12);
|
|
}
|
|
|
|
// note: if adding attributes with flobs, the value mapping must be changed
|
|
|
|
ValueMapping mcreatemtreeVM[] = {
|
|
mcreatemtreeVMTStream<mtreehelper::t1>,
|
|
mcreatemtreeVMTStream<mtreehelper::t2>,
|
|
mcreatemtreeVMTStream<mtreehelper::t3>,
|
|
mcreatemtreeVMTStream<mtreehelper::t4>,
|
|
mcreatemtreeVMTStream<mtreehelper::t5>,
|
|
mcreatemtreeVMTStream<mtreehelper::t6>,
|
|
mcreatemtreeVMTStream<mtreehelper::t7>,
|
|
mcreatemtreeVMTStream<mtreehelper::t8>,
|
|
mcreatemtreeVMTStream<mtreehelper::t9>,
|
|
mcreatemtreeVMTStream<mtreehelper::t10>,
|
|
mcreatemtreeVMTStream<mtreehelper::t11>,
|
|
mcreatemtreeVMTStream<mtreehelper::t12>,
|
|
mcreatemtreeVMTMP<mtreehelper::t1>,
|
|
mcreatemtreeVMTMP<mtreehelper::t2>,
|
|
mcreatemtreeVMTMP<mtreehelper::t3>,
|
|
mcreatemtreeVMTMP<mtreehelper::t4>,
|
|
mcreatemtreeVMTMP<mtreehelper::t5>,
|
|
mcreatemtreeVMTMP<mtreehelper::t6>,
|
|
mcreatemtreeVMTMP<mtreehelper::t7>,
|
|
mcreatemtreeVMTMP<mtreehelper::t8>,
|
|
mcreatemtreeVMTMP<mtreehelper::t9>,
|
|
mcreatemtreeVMTMP<mtreehelper::t10>,
|
|
mcreatemtreeVMTMP<mtreehelper::t11>,
|
|
mcreatemtreeVMTMP<mtreehelper::t12>
|
|
};
|
|
|
|
OperatorSpec mcreatemtreeSpec(
|
|
"stream(tuple) x attrname x attrname [x geoid] -> mpointer(mem(mtree X))||\n"
|
|
"MREL(tuple) x attrname [x geoid] -> , mpointer(mem(mtree X))",
|
|
"tuplestream mcreatemtree[ indexAttr, TID_attr [, geoid] ] ||\n"
|
|
"mrel mcreatemtree[indexAttr [, geoid] ]",
|
|
"This operator creates an m-tree in main memory. "
|
|
"The first argument is a stream or a main memory relation containing the "
|
|
"tuples to be indexed. The second argument refers to the attribute "
|
|
"over that the index is built. If the tuples are provided as a stream, "
|
|
"the third argument refers to an attribute inside the tuple containg its "
|
|
"tuple id. The last argument is optional. It must be of type geoid and "
|
|
"can only be used if the index-attribute is of type point, mpoint, cupoint, "
|
|
"or cmpoint. If this argument is present, the distance between two objects "
|
|
"is computed as geographic distance on this geoid instead of using the "
|
|
"Euclidean distance.\n In detail, the following types are supported:\n\n"
|
|
" * point: p1->Distance(*p2, geoid)\n"
|
|
" * string: stringutils::ld->(s1->GetValue(), s2->GetValue())\n"
|
|
" * int: abs(i1->GetValue() - i2->GetValue())\n"
|
|
" * real: abs(r1->GetValue() - r2->GetValue())\n"
|
|
" * rect<d>: r1->Distance(*r2)\n"
|
|
" * mpoint: mp1->DistanceAvg(*mp2, geoid)\n"
|
|
" * cupoint: cup1->DistanceAvg(*cup2, false, geoid)\n"
|
|
" * cmpoint: cmp1->DistanceAvg(*cmp2, false, geoid)\n",
|
|
"let kinos_mtree_GeoData = kinos feed addid mcreatemtree[GeoData, TID]"
|
|
);
|
|
|
|
Operator mcreatemtreeOp(
|
|
"mcreatemtree",
|
|
mcreatemtreeSpec.getStr(),
|
|
24,
|
|
mcreatemtreeVM,
|
|
mcreatemtreeSelect,
|
|
mcreatemtreeTM
|
|
);
|
|
|
|
/*
|
|
Operator ~mcreatemtree2~
|
|
|
|
6.1 Type Mapping
|
|
|
|
*/
|
|
ListExpr mcreatemtree2TM(ListExpr args) {
|
|
string err= "expected: stream(tuple) x attrname x attrname x attrname x real "
|
|
"[x geoid]\n or MREL x attrname x attrname x real [x geoid]";
|
|
if (!nl->HasMinLength(args, 4)) {
|
|
return listutils::typeError(err+" (less than 4 arguments)");
|
|
}
|
|
bool isTS = Stream<Tuple>::checkType(nl->First(args));
|
|
bool isMP = MPointer::checkType(nl->First(args));
|
|
if (!isTS && !isMP) {
|
|
return listutils::typeError(err + " (first arg is neither a tuple stream "
|
|
"nor an mpointer)");
|
|
}
|
|
if (nl->AtomType(nl->Second(args)) != SymbolType){
|
|
return listutils::typeError(err + " (second argument is not a valid "
|
|
"attribute name)");
|
|
}
|
|
if (nl->AtomType(nl->Third(args)) != SymbolType) {
|
|
return listutils::typeError(err + " (third argument is not a valid "
|
|
"attribute name)");
|
|
}
|
|
if (isTS) {
|
|
if(!nl->HasLength(args, 5) && !nl->HasLength(args, 6)) {
|
|
return listutils::typeError("for a tuple stream, "
|
|
"5 or 6 arguments are required");
|
|
}
|
|
if (nl->AtomType(nl->Fourth(args)) != SymbolType) {
|
|
return listutils::typeError(err + " (fourth argument is not a valid "
|
|
"attribute name)");
|
|
}
|
|
if (!CcReal::checkType(nl->Fifth(args))) {
|
|
return listutils::typeError(err + " (fifth argument is not a real)");
|
|
}
|
|
if (nl->HasLength(args, 6)) {
|
|
if (!Geoid::checkType(nl->Sixth(args))) {
|
|
return listutils::typeError(" (sixth argument is not a geoid)");
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
if (!nl->HasLength(args, 4) && !nl->HasLength(args, 5)) {
|
|
return listutils::typeError("for an mpointer, 4 or 5 "
|
|
" arguments are required");
|
|
}
|
|
if (nl->HasLength(args, 5)) {
|
|
if (!Geoid::checkType(nl->Fifth(args))) {
|
|
return listutils::typeError("fifth argument is not a geoid");
|
|
}
|
|
}
|
|
}
|
|
// extract tuple type from first argument
|
|
ListExpr tupletype;
|
|
if (isMP) {
|
|
ListExpr mpt = nl->Second(nl->Second(nl->First(args)));
|
|
if (!Relation::checkType(mpt)) {
|
|
return listutils::typeError("mpointer to a non-relation");
|
|
}
|
|
tupletype = nl->Second(mpt);
|
|
}
|
|
else {
|
|
tupletype = nl->Second(nl->First(args));
|
|
}
|
|
ListExpr attrList = nl->Second(tupletype);
|
|
string mpName = nl->SymbolValue(nl->Second(args));
|
|
ListExpr type;
|
|
int index1 = listutils::findAttribute(attrList, mpName, type);
|
|
if (!index1) {
|
|
return listutils::typeError("attr " + mpName + " not part of the tuple");
|
|
}
|
|
if(!temporalalgebra::MPoint::checkType(type) &&
|
|
!temporalalgebra::CUPoint::checkType(type) &&
|
|
!temporalalgebra::CMPoint::checkType(type)) {
|
|
return listutils::typeError(" support only for (m|cu|cm)point");
|
|
}
|
|
string mlName = nl->SymbolValue(nl->Third(args));
|
|
int index2 = listutils::findAttribute(attrList, mlName, type);
|
|
if (!index2) {
|
|
return listutils::typeError("attr " + mlName + " not part of the tuple");
|
|
}
|
|
if (!stj::isSymbolicType(type)) {
|
|
return listutils::typeError(" support only for mlabel(s) or mplace(s)");
|
|
}
|
|
int index3 = -1;
|
|
if (isTS) {
|
|
string tidname = nl->SymbolValue(nl->Fourth(args));
|
|
ListExpr tidtype;
|
|
index3 = listutils::findAttribute(attrList, tidname, tidtype);
|
|
if (!index3) {
|
|
return listutils::typeError("attribute " + tidname + " does not exist");
|
|
}
|
|
if (!TupleIdentifier::checkType(tidtype)) {
|
|
return listutils::typeError("attribute " + tidname + " not of type tid");
|
|
}
|
|
}
|
|
ListExpr resType = MPointer::wrapType(
|
|
Mem::wrapType(
|
|
nl->TwoElemList(
|
|
listutils::basicSymbol<
|
|
MemoryMtreeObject<Point,
|
|
StdDistComp<Point> > >(),
|
|
nl->SymbolAtom("tuple")
|
|
)));
|
|
ListExpr appendList;
|
|
if (isTS) {
|
|
appendList = nl->ThreeElemList(nl->IntAtom(index1 - 1),
|
|
nl->IntAtom(index2 - 1),
|
|
nl->IntAtom(index3 - 1));
|
|
}
|
|
else {
|
|
appendList = nl->TwoElemList(nl->IntAtom(index1 - 1),
|
|
nl->IntAtom(index2 - 1));
|
|
}
|
|
ListExpr result = nl->ThreeElemList(nl->SymbolAtom(Symbols::APPEND()),
|
|
appendList,
|
|
resType);
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
6.2 Value Mapping functions
|
|
|
|
*/
|
|
template<class Spa, class Sym>
|
|
int mcreatemtree2StreamVM(Word* args, Word& result, int message, Word& local,
|
|
Supplier s) {
|
|
result = qp->ResultStorage(s);
|
|
MPointer* res = (MPointer*)result.addr;
|
|
Geoid *geoid = 0;
|
|
int offset = 0;
|
|
if (qp->GetNoSons(s) == 9) { // 6 given, 3 additional
|
|
geoid = (Geoid*)args[5].addr;
|
|
if (!geoid->IsDefined()) {
|
|
geoid = 0;
|
|
}
|
|
offset++;
|
|
}
|
|
CcReal* alphacc = (CcReal*)args[4].addr;
|
|
if (!alphacc->IsDefined()) {
|
|
return 0;
|
|
}
|
|
double alpha = alphacc->GetValue();
|
|
if (alpha < 0.0 || alpha > 1.0) {
|
|
cout << "alpha must be in [0, 1]" << endl;
|
|
return 0;
|
|
}
|
|
int indexSpa = ((CcInt*)args[5 + offset].addr)->GetValue();
|
|
int indexSym = ((CcInt*)args[6 + offset].addr)->GetValue();
|
|
int indexTID = ((CcInt*)args[7 + offset].addr)->GetValue();
|
|
StdDistCompExt<Spa, Sym> dc(geoid, alpha);
|
|
MMMTree<MTreeEntry<pair<Spa, Sym> >, StdDistCompExt<Spa, Sym> >* tree =
|
|
new MMMTree<MTreeEntry<pair<Spa, Sym> >, StdDistCompExt<Spa, Sym> >(4,8,dc);
|
|
// typedef pair<pair<Spa, Sym>, TupleId> treeentry_t;
|
|
// MMMTree<treeentry_t, StdDistCompExt<Spa, Sym>,
|
|
// MemCloner<treeentry_t> >* tree =
|
|
// new MMMTree<treeentry_t,
|
|
// StdDistCompExt<Spa, Sym>,
|
|
// MemCloner<treeentry_t> >(4, 8, dc);
|
|
Stream<Tuple> stream(args[0]);
|
|
stream.open();
|
|
Tuple* tuple;
|
|
bool flobused = false;
|
|
Spa* spa = 0;
|
|
Sym *sym = 0;
|
|
while ((tuple = stream.request())) {
|
|
spa = (Spa*)(tuple->GetAttribute(indexSpa));
|
|
sym = (Sym*)(tuple->GetAttribute(indexSym));
|
|
TupleIdentifier* tid = (TupleIdentifier*)(tuple->GetAttribute(indexTID));
|
|
if (tid->IsDefined()) {
|
|
Spa copySpa = *spa;
|
|
Sym copySym = *sym;
|
|
flobused = flobused || copySpa.NumOfFLOBs() > 0 ||
|
|
copySym.NumOfFLOBs() > 0;
|
|
pair<Spa, Sym> spasym(copySpa, copySym);
|
|
MTreeEntry<pair<Spa, Sym> > entry(spasym, tid->GetTid());
|
|
// pair<pair<Spa, Sym>, TupleId> p(spasym, tid->GetTid());
|
|
tree->insert(entry);
|
|
entry.Destroy();
|
|
}
|
|
tuple->DeleteIfAllowed();
|
|
}
|
|
stream.close();
|
|
size_t usedMem = tree->memSize();
|
|
ListExpr typeList = nl->Second(qp->GetType(s));
|
|
MemoryMtreeObject<pair<Spa, Sym>, StdDistCompExt<Spa, Sym> >*
|
|
mtree = new MemoryMtreeObject<pair<Spa, Sym>, StdDistCompExt<Spa, Sym> >
|
|
(tree, usedMem, nl->ToString(typeList), !flobused, getDBname());
|
|
mtreehelper::increaseCounter("counterMCreateMTree",
|
|
mtree->getmtree()->getDistComp().getNoDistFunCalls());
|
|
res->setPointer(mtree);
|
|
mtree->deleteIfAllowed();
|
|
return 0;
|
|
}
|
|
|
|
template<class Spa, class Sym>
|
|
int mcreatemtree2MRelVM(Word* args, Word& result, int message, Word& local,
|
|
Supplier s) {
|
|
result = qp->ResultStorage(s);
|
|
MPointer* res = (MPointer*)result.addr;
|
|
MPointer* mrelp = (MPointer*)args[0].addr;
|
|
if (mrelp->isNull()) {
|
|
res->setPointer(0);
|
|
return 0;
|
|
}
|
|
Geoid *geoid = 0;
|
|
int offset = 0;
|
|
if (qp->GetNoSons(s) == 7) { // 5 given, 2 additional
|
|
geoid = (Geoid*)args[4].addr;
|
|
if (!geoid->IsDefined()) {
|
|
geoid = 0;
|
|
}
|
|
offset++;
|
|
}
|
|
CcReal* alphacc = (CcReal*)args[3].addr;
|
|
if (!alphacc->IsDefined()) {
|
|
return 0;
|
|
}
|
|
double alpha = alphacc->GetValue();
|
|
if (alpha < 0.0 || alpha > 1.0) {
|
|
cout << "alpha must be in [0, 1]" << endl;
|
|
return 0;
|
|
}
|
|
int indexSpa = ((CcInt*)args[4 + offset].addr)->GetValue();
|
|
int indexSym = ((CcInt*)args[5 + offset].addr)->GetValue();
|
|
MemoryRelObject* mrel = (MemoryRelObject*) mrelp->GetValue();
|
|
vector<Tuple*>* v = mrel->getmmrel();
|
|
StdDistCompExt<Spa, Sym> dc(geoid, alpha);
|
|
MMMTree<MTreeEntry<pair<Spa, Sym> >, StdDistCompExt<Spa, Sym> >* tree =
|
|
new MMMTree<MTreeEntry<pair<Spa, Sym> >, StdDistCompExt<Spa, Sym> >(4,8,dc);
|
|
// typedef pair<pair<Spa, Sym>, TupleId> treeentry_t;
|
|
// MMMTree<treeentry_t, StdDistCompExt<Spa, Sym>,
|
|
// MemCloner<treeentry_t> >* tree =
|
|
// new MMMTree<treeentry_t,
|
|
// StdDistCompExt<Spa, Sym>,
|
|
// MemCloner<treeentry_t> >(4, 8, dc);
|
|
Tuple* tuple;
|
|
bool flobused = false;
|
|
Spa* spa = 0;
|
|
Sym* sym = 0;
|
|
if (v) {
|
|
for(size_t i = 0; i < v->size(); i++) {
|
|
tuple = v->at(i);
|
|
if (tuple) {
|
|
spa = (Spa*)tuple->GetAttribute(indexSpa);
|
|
sym = (Sym*)tuple->GetAttribute(indexSym);
|
|
Spa copySpa = *spa;
|
|
Sym copySym = *sym;
|
|
pair<Spa, Sym> spasym(copySpa, copySym);
|
|
MTreeEntry<pair<Spa, Sym> > entry(spasym, i + 1);
|
|
// pair<pair<Spa, Sym>, TupleId> p(spasym, i + 1);
|
|
tree->insert(entry);
|
|
entry.Destroy();
|
|
}
|
|
}
|
|
}
|
|
size_t usedMem = tree->memSize();
|
|
ListExpr typeList = nl->Second(qp->GetType(s));
|
|
MemoryMtreeObject<pair<Spa, Sym>, StdDistCompExt<Spa, Sym> >*
|
|
mtree = new MemoryMtreeObject<pair<Spa, Sym>, StdDistCompExt<Spa, Sym> >
|
|
(tree, usedMem, nl->ToString(typeList), !flobused, getDBname());
|
|
mtreehelper::increaseCounter("counterMCreateMTree",
|
|
mtree->getmtree()->getDistComp().getNoDistFunCalls());
|
|
res->setPointer(mtree);
|
|
mtree->deleteIfAllowed();
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
6.3 Selection Function and Value Mapping Array
|
|
|
|
*/
|
|
int mcreatemtree2Select(ListExpr args) {
|
|
bool isStream = Stream<Tuple>::checkType(nl->First(args));
|
|
ListExpr tupletype;
|
|
int noSymTypes = 4;
|
|
int noSpaTypes = 3;
|
|
int offset = 0;
|
|
if (!isStream) {
|
|
tupletype = nl->Second(nl->Second(nl->Second(nl->First(args))));
|
|
offset = noSymTypes * noSpaTypes;
|
|
}
|
|
else {
|
|
tupletype = nl->Second(nl->First(args));
|
|
}
|
|
ListExpr attrList = nl->Second(tupletype);
|
|
string symName = nl->SymbolValue(nl->Third(args));
|
|
ListExpr type;
|
|
listutils::findAttribute(attrList, symName, type);
|
|
int symbolicType;
|
|
if (stj::MLabel::checkType(type)) {
|
|
symbolicType = 0;
|
|
}
|
|
if (stj::MLabels::checkType(type)) {
|
|
symbolicType = 1;
|
|
}
|
|
if (stj::MPlace::checkType(type)) {
|
|
symbolicType = 2;
|
|
}
|
|
if (stj::MPlaces::checkType(type)) {
|
|
symbolicType = 3;
|
|
}
|
|
string spaName = nl->SymbolValue(nl->Second(args));
|
|
listutils::findAttribute(attrList, spaName, type);
|
|
if (temporalalgebra::MPoint::checkType(type)) {
|
|
return symbolicType + offset;
|
|
}
|
|
if (temporalalgebra::CUPoint::checkType(type)) {
|
|
return noSymTypes + symbolicType + offset;
|
|
}
|
|
if (temporalalgebra::CMPoint::checkType(type)) {
|
|
return 2 * noSymTypes + symbolicType + offset;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
ValueMapping mcreatemtree2VMs[] = {
|
|
mcreatemtree2StreamVM<temporalalgebra::MPoint, stj::MLabel>,
|
|
mcreatemtree2StreamVM<temporalalgebra::MPoint, stj::MLabels>,
|
|
mcreatemtree2StreamVM<temporalalgebra::MPoint, stj::MPlace>,
|
|
mcreatemtree2StreamVM<temporalalgebra::MPoint, stj::MPlaces>,
|
|
mcreatemtree2StreamVM<temporalalgebra::CUPoint, stj::MLabel>,
|
|
mcreatemtree2StreamVM<temporalalgebra::CUPoint, stj::MLabels>,
|
|
mcreatemtree2StreamVM<temporalalgebra::CUPoint, stj::MPlace>,
|
|
mcreatemtree2StreamVM<temporalalgebra::CUPoint, stj::MPlaces>,
|
|
mcreatemtree2StreamVM<temporalalgebra::CMPoint, stj::MLabel>,
|
|
mcreatemtree2StreamVM<temporalalgebra::CMPoint, stj::MLabels>,
|
|
mcreatemtree2StreamVM<temporalalgebra::CMPoint, stj::MPlace>,
|
|
mcreatemtree2StreamVM<temporalalgebra::CMPoint, stj::MPlaces>,
|
|
mcreatemtree2MRelVM<temporalalgebra::MPoint, stj::MLabel>,
|
|
mcreatemtree2MRelVM<temporalalgebra::MPoint, stj::MLabels>,
|
|
mcreatemtree2MRelVM<temporalalgebra::MPoint, stj::MPlace>,
|
|
mcreatemtree2MRelVM<temporalalgebra::MPoint, stj::MPlaces>,
|
|
mcreatemtree2MRelVM<temporalalgebra::CUPoint, stj::MLabel>,
|
|
mcreatemtree2MRelVM<temporalalgebra::CUPoint, stj::MLabels>,
|
|
mcreatemtree2MRelVM<temporalalgebra::CUPoint, stj::MPlace>,
|
|
mcreatemtree2MRelVM<temporalalgebra::CUPoint, stj::MPlaces>,
|
|
mcreatemtree2MRelVM<temporalalgebra::CMPoint, stj::MLabel>,
|
|
mcreatemtree2MRelVM<temporalalgebra::CMPoint, stj::MLabels>,
|
|
mcreatemtree2MRelVM<temporalalgebra::CMPoint, stj::MPlace>,
|
|
mcreatemtree2MRelVM<temporalalgebra::CMPoint, stj::MPlaces>
|
|
};
|
|
|
|
OperatorSpec mcreatemtree2Spec(
|
|
"stream(tuple) x attrname x attrname x attrname x real [x geoid] -> "
|
|
"mpointer(mem(mtree tuple))||\n"
|
|
"MREL(tuple) x attrname x attrname x real [x geoid] -> "
|
|
"mpointer(mem(mtree tuple))",
|
|
"tuplestream mcreatemtree2[Spatiotemp_attr, Symbolic_attr, TID_attr, alpha "
|
|
"[, geoid] ] ||\n"
|
|
"mrel mcreatemtree2[MPoint_attr, MLabel_attr, alpha [, geoid] ]",
|
|
"This operator creates an m-tree in main memory. "
|
|
"The first argument is a stream or a main memory relation containing the "
|
|
"tuples to be indexed. The second and third arguments refer to the attributes"
|
|
" of the types mpoint/cupoint/cmpoint and mlabel(s)/mplace(s), respectively. "
|
|
"If the tuples are provided as a stream, the fourth argument refers to a "
|
|
"tuple id attribute. The fifth argument is a real number in [0,1] controlling"
|
|
"the distance function ratio. The sixth argument is optional and must be of "
|
|
"type geoid. If it is present, the distance between two objects is computed "
|
|
"as geographic distance on this geoid instead of using the Euclidean "
|
|
"distance.\n The following types are supported with respective functions:\n\n"
|
|
" Spatial Types (first attribute name):\n"
|
|
" * mpoint: DistanceAvg (geoid supported)\n"
|
|
" * cupoint: DistanceAvgLB (geoid supported)\n"
|
|
" * cmpoint: DistanceAvgLB (geoid supported)\n\n"
|
|
" Symbolic Types (second attribute name):\n"
|
|
" * mlabel: Jaccard Similarity\n"
|
|
" * mlabels: Jaccard Similarity\n"
|
|
" * mplace: Jaccard Similarity\n"
|
|
" * mplaces: Jaccard Similarity\n",
|
|
"let kinos_mtree_GeoData = kinos feed addid mcreatemtree[GeoData, TID]"
|
|
);
|
|
|
|
Operator mcreatemtree2Op(
|
|
"mcreatemtree2",
|
|
mcreatemtree2Spec.getStr(),
|
|
24,
|
|
mcreatemtree2VMs,
|
|
mcreatemtree2Select,
|
|
mcreatemtree2TM
|
|
);
|
|
|
|
|
|
/*
|
|
Operator ~minsertmtree~
|
|
|
|
*/
|
|
|
|
ListExpr minsertmtreeTM(ListExpr args){
|
|
if(!nl->HasLength(args,3)){
|
|
return listutils::typeError("three arguments required");
|
|
}
|
|
ListExpr a1 = nl->First(args);
|
|
if(!Stream<Tuple>::checkType(a1)){
|
|
return listutils::typeError("first argument is not a tuple stream");
|
|
}
|
|
ListExpr a2 = nl->Second(args);
|
|
|
|
if(MPointer::checkType(a2)){
|
|
a2 = nl->Second(a2);
|
|
}
|
|
if(!Mem::checkType(a2)){
|
|
return listutils::typeError("arg 2 is not a memory object");
|
|
}
|
|
a2 = nl->Second(a2); // remove mem
|
|
|
|
ListExpr a3 = nl->Third(args);
|
|
if(!listutils::isSymbol(a3)){
|
|
return listutils::typeError("third arg is not a valid attribute name");
|
|
}
|
|
|
|
ListExpr attrList = nl->Second(nl->Second(a1));
|
|
ListExpr attrType;
|
|
string attrName = nl->SymbolValue(a3);
|
|
int attrIndex = listutils::findAttribute(attrList, attrName, attrType);
|
|
if(!attrIndex){
|
|
return listutils::typeError("attribute name " + attrName
|
|
+ " not part of the tuple");
|
|
}
|
|
ListExpr tt = nl->TwoElemList(nl->SymbolAtom(mtreehelper::BasicType()),
|
|
attrType);
|
|
if(!nl->Equal(a2,tt)){
|
|
return listutils::typeError("second arg is not an memory mtree over "
|
|
+ nl->ToString(attrType));
|
|
}
|
|
ListExpr tidType;
|
|
int tidIndex = listutils::findAttribute(attrList, "TID", tidType);
|
|
if(tidIndex==0){
|
|
return listutils::typeError("no TID attribute found");
|
|
}
|
|
if(!TupleIdentifier::checkType(tidType)){
|
|
return listutils::typeError("TID attribute not of tpye tid");
|
|
}
|
|
|
|
|
|
ListExpr appendList = nl->TwoElemList(nl->IntAtom(attrIndex -1),
|
|
nl->IntAtom(tidIndex -1));
|
|
return nl->ThreeElemList(
|
|
nl->SymbolAtom(Symbols::APPEND()),
|
|
appendList,
|
|
nl->First(args));
|
|
}
|
|
|
|
|
|
template<class T>
|
|
class minsertmtreeInfo{
|
|
typedef StdDistComp<T> D;
|
|
|
|
public:
|
|
minsertmtreeInfo(Word _stream,
|
|
MemoryMtreeObject<T,D >* _tree,
|
|
int _index, int _tidIndex): stream(_stream) {
|
|
tree = _tree->getmtree();
|
|
index = _index;
|
|
tidIndex = _tidIndex;
|
|
stream.open();
|
|
}
|
|
|
|
~minsertmtreeInfo(){
|
|
stream.close();
|
|
}
|
|
|
|
Tuple* next(){
|
|
Tuple* in = stream.request();
|
|
if(!in) return 0;
|
|
TupleIdentifier* tid = (TupleIdentifier*) in->GetAttribute(tidIndex);
|
|
if(!tid->IsDefined()){
|
|
return in;
|
|
}
|
|
TupleId id = tid->GetTid();
|
|
if(id!=0){ // do not insert 0 id
|
|
T* attr = (T*) in->GetAttribute(index);
|
|
MTreeEntry<T> p(*attr, id);
|
|
// pair<T,TupleId> p(*attr,id);
|
|
tree->insert(p);
|
|
}
|
|
return in;
|
|
}
|
|
|
|
|
|
private:
|
|
Stream<Tuple> stream;
|
|
MMMTree<MTreeEntry<T>, StdDistComp<T> >* tree;
|
|
// MMMTree<std::pair<T, TupleId>, StdDistComp<T>,
|
|
// MemCloner<std::pair<T, TupleId> > >* tree;
|
|
int index;
|
|
int tidIndex;
|
|
|
|
};
|
|
|
|
|
|
template<class T, class N>
|
|
int minsertmtreeVMT (Word* args, Word& result, int message,
|
|
Word& local, Supplier s) {
|
|
|
|
typedef StdDistComp<T> D;
|
|
minsertmtreeInfo<T >* li = (minsertmtreeInfo<T>*) local.addr;
|
|
switch(message){
|
|
case OPEN : { if(li){
|
|
delete li;
|
|
}
|
|
int index = ((CcInt*) args[3].addr)->GetValue();
|
|
int tidIndex = ((CcInt*) args[4].addr)->GetValue();
|
|
N* n = (N*) args[1].addr;
|
|
MemoryMtreeObject<T,D>* tree = getMtree<N,T>(n);
|
|
local.addr = new minsertmtreeInfo<T>(args[0], tree,
|
|
index, tidIndex);
|
|
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;
|
|
}
|
|
|
|
|
|
ValueMapping minsertmtreeVM[] = {
|
|
minsertmtreeVMT<mtreehelper::t1,Mem>,
|
|
minsertmtreeVMT<mtreehelper::t2,Mem>,
|
|
minsertmtreeVMT<mtreehelper::t3,Mem>,
|
|
minsertmtreeVMT<mtreehelper::t4,Mem>,
|
|
minsertmtreeVMT<mtreehelper::t5,Mem>,
|
|
minsertmtreeVMT<mtreehelper::t6,Mem>,
|
|
minsertmtreeVMT<mtreehelper::t7,Mem>,
|
|
minsertmtreeVMT<mtreehelper::t8,Mem>,
|
|
minsertmtreeVMT<mtreehelper::t9,Mem>,
|
|
minsertmtreeVMT<mtreehelper::t10,Mem>,
|
|
minsertmtreeVMT<mtreehelper::t11,Mem>,
|
|
minsertmtreeVMT<mtreehelper::t12,Mem>,
|
|
minsertmtreeVMT<mtreehelper::t1,MPointer>,
|
|
minsertmtreeVMT<mtreehelper::t2,MPointer>,
|
|
minsertmtreeVMT<mtreehelper::t3,MPointer>,
|
|
minsertmtreeVMT<mtreehelper::t4,MPointer>,
|
|
minsertmtreeVMT<mtreehelper::t5,MPointer>,
|
|
minsertmtreeVMT<mtreehelper::t6,MPointer>,
|
|
minsertmtreeVMT<mtreehelper::t7,MPointer>,
|
|
minsertmtreeVMT<mtreehelper::t8,MPointer>,
|
|
minsertmtreeVMT<mtreehelper::t9,MPointer>,
|
|
minsertmtreeVMT<mtreehelper::t10,MPointer>,
|
|
minsertmtreeVMT<mtreehelper::t11,MPointer>,
|
|
minsertmtreeVMT<mtreehelper::t12,MPointer>
|
|
};
|
|
|
|
int minsertmtreeSelect(ListExpr args){
|
|
int o1 = Mem::checkType(nl->Second(args))?0:12;
|
|
string attrName = nl->SymbolValue(nl->Third(args));
|
|
ListExpr attrList = nl->Second(nl->Second(nl->First(args)));
|
|
ListExpr type;
|
|
listutils::findAttribute(attrList, attrName, type);
|
|
return o1 + mtreehelper::getTypeNo(type,12);
|
|
}
|
|
|
|
OperatorSpec minsertmtreeSpec(
|
|
"stream(tuple(x@TID)) x MMTREE x IDENT -> stream(tuple(x@TID))",
|
|
"_ minsertmtree[ _ , _ ]",
|
|
"Inserts the tuples from a stream into an existing main memory mtree."
|
|
"TupleIDs are extracted from the TID attribute expected in the tuple. "
|
|
"Tuples with an undefined id or an id of value 0 are not inserted "
|
|
"into the tree. All incoming tuples are put into the output stream.",
|
|
"query plz feed addid minsertmtree[plz_PLZ_mtree, PLZ] count"
|
|
);
|
|
|
|
Operator minsertmtreeOp(
|
|
"minsertmtree",
|
|
minsertmtreeSpec.getStr(),
|
|
24,
|
|
minsertmtreeVM,
|
|
minsertmtreeSelect,
|
|
minsertmtreeTM
|
|
);
|
|
|
|
|
|
|
|
/*
|
|
Operator ~mdistRange2~
|
|
|
|
This operator creates a stream of TupleIDs that are inside a
|
|
given distance to a reference object. The used index is a
|
|
main memory based mtree.
|
|
|
|
*/
|
|
template<bool wrap>
|
|
ListExpr mdistRange2TM(ListExpr args){
|
|
|
|
string err = "MTREE(T) x T x real expected";
|
|
if(!nl->HasLength(args,3)){
|
|
return listutils::typeError(err + " ( wrong number of args)");
|
|
}
|
|
ListExpr a1 = nl->First(args);
|
|
if(MPointer::checkType(a1)){
|
|
a1 = nl->Second(a1);
|
|
}
|
|
if(!Mem::checkType(a1)){
|
|
return listutils::typeError("arg 1 is not a memory object");
|
|
}
|
|
a1 = nl->Second(a1); // remove mem
|
|
ListExpr mt = nl->TwoElemList(
|
|
nl->SymbolAtom(mtreehelper::BasicType()),
|
|
nl->Second(args));
|
|
|
|
if(!nl->Equal(a1, mt)){
|
|
return listutils::typeError("arg 1 is not an mtree over arg 2 ("
|
|
+ nl->ToString(nl->First(nl->Second(args)))
|
|
+ ")");
|
|
}
|
|
if(!CcReal::checkType(nl->Third(args))){
|
|
return listutils::typeError(err + " (third arg is not a real)");
|
|
}
|
|
if(!wrap){
|
|
return nl->TwoElemList(
|
|
listutils::basicSymbol<Stream<TupleIdentifier> >(),
|
|
listutils::basicSymbol<TupleIdentifier>());
|
|
} else {
|
|
ListExpr attrList = nl->OneElemList(
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom("TID"),
|
|
listutils::basicSymbol<TupleIdentifier>()));
|
|
return nl->TwoElemList(
|
|
listutils::basicSymbol<Stream<Tuple> >(),
|
|
nl->TwoElemList(
|
|
listutils::basicSymbol<Tuple>(),
|
|
attrList));
|
|
}
|
|
}
|
|
|
|
template<class T>
|
|
struct mdistrange2Info{
|
|
RangeIterator<MTreeEntry<T>, StdDistComp<T> >* it;
|
|
TupleType* tt;
|
|
};
|
|
|
|
|
|
template <class T, class N, bool wrap>
|
|
int mdistRange2VMT (Word* args, Word& result, int message,
|
|
Word& local, Supplier s) {
|
|
|
|
mdistrange2Info<T>* li = (mdistrange2Info<T>*) local.addr;
|
|
switch(message){
|
|
case OPEN: {
|
|
if(li) {
|
|
delete li->it;
|
|
if(li->tt){
|
|
li->tt->DeleteIfAllowed();
|
|
}
|
|
local.addr = 0;
|
|
}
|
|
|
|
T* attr = (T*) args[1].addr;
|
|
CcReal* dist = (CcReal*) args[2].addr;
|
|
if(!dist->IsDefined()){
|
|
return 0;
|
|
}
|
|
double d = dist->GetValue();
|
|
if(d < 0){
|
|
return 0;
|
|
}
|
|
N* tree = (N*) args[0].addr;
|
|
typedef MemoryMtreeObject<T,StdDistComp<T> > mtot;
|
|
mtot* mtreeo = getMtree<N,T>(tree);
|
|
if(!mtreeo){
|
|
return 0;
|
|
}
|
|
typedef MMMTree<MTreeEntry<T>, StdDistComp<T> > mtt;
|
|
// typedef MMMTree<pair<T,TupleId>,StdDistComp<T>,
|
|
// MemCloner<pair<T,TupleId>> > mtt;
|
|
mtt* mtree = mtreeo->getmtree();
|
|
if(mtree){
|
|
T a = *attr;
|
|
mdistrange2Info<T>* info = new mdistrange2Info<T>();
|
|
MTreeEntry<T> entry(a, 0);
|
|
info->it = mtree->rangeSearch(entry, d);
|
|
// info->it = mtree->rangeSearch(pair<T,TupleId>(a,0), d);
|
|
if(!wrap){
|
|
info->tt = 0;
|
|
} else {
|
|
info->tt = new TupleType(nl->Second(GetTupleResultType(s)));
|
|
}
|
|
local.addr = info;
|
|
}
|
|
return 0;
|
|
}
|
|
case REQUEST: {
|
|
if(!li){
|
|
result.addr=0;
|
|
return CANCEL;
|
|
}
|
|
const MTreeEntry<T>* n = li->it->next();
|
|
TupleIdentifier* res = n ?
|
|
new TupleIdentifier(true, n->getTid()) : 0;
|
|
if(!res){
|
|
result.addr=0;
|
|
return CANCEL;
|
|
}
|
|
if(!wrap){
|
|
result.addr = res;
|
|
} else {
|
|
Tuple* tuple = new Tuple(li->tt);
|
|
tuple->PutAttribute(0,res);
|
|
result.addr = tuple;
|
|
}
|
|
return result.addr?YIELD:CANCEL;
|
|
}
|
|
case CLOSE:
|
|
if(li){
|
|
delete li->it;
|
|
if(li->tt){
|
|
li->tt->DeleteIfAllowed();
|
|
}
|
|
delete li;
|
|
local.addr = 0;
|
|
}
|
|
return 0;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
6.3 Selection and Value Mapping Array
|
|
|
|
*/
|
|
int mdistRange2Select(ListExpr args){
|
|
ListExpr type = nl->Second(args);
|
|
int n;
|
|
if(Mem::checkType(nl->First(args))){
|
|
n = 0;
|
|
} else { // MPointer variant
|
|
n = 12;
|
|
}
|
|
int res = mtreehelper::getTypeNo(type,12) + n;
|
|
return res;
|
|
}
|
|
|
|
// note: if adding attributes with flobs, the value mapping must be changed
|
|
|
|
ValueMapping mdistRange2VM[] = {
|
|
mdistRange2VMT<mtreehelper::t1, Mem, true>,
|
|
mdistRange2VMT<mtreehelper::t2, Mem, true>,
|
|
mdistRange2VMT<mtreehelper::t3, Mem, true>,
|
|
mdistRange2VMT<mtreehelper::t4, Mem, true>,
|
|
mdistRange2VMT<mtreehelper::t5, Mem, true>,
|
|
mdistRange2VMT<mtreehelper::t6, Mem, true>,
|
|
mdistRange2VMT<mtreehelper::t7, Mem, true>,
|
|
mdistRange2VMT<mtreehelper::t8, Mem, true>,
|
|
mdistRange2VMT<mtreehelper::t9, Mem, true>,
|
|
mdistRange2VMT<mtreehelper::t10, Mem, true>,
|
|
mdistRange2VMT<mtreehelper::t11, Mem, true>,
|
|
mdistRange2VMT<mtreehelper::t12, Mem, true>,
|
|
|
|
mdistRange2VMT<mtreehelper::t1, MPointer, true>,
|
|
mdistRange2VMT<mtreehelper::t2, MPointer, true>,
|
|
mdistRange2VMT<mtreehelper::t3, MPointer, true>,
|
|
mdistRange2VMT<mtreehelper::t4, MPointer, true>,
|
|
mdistRange2VMT<mtreehelper::t5, MPointer, true>,
|
|
mdistRange2VMT<mtreehelper::t6, MPointer, true>,
|
|
mdistRange2VMT<mtreehelper::t7, MPointer, true>,
|
|
mdistRange2VMT<mtreehelper::t8, MPointer, true>,
|
|
mdistRange2VMT<mtreehelper::t9, MPointer, true>,
|
|
mdistRange2VMT<mtreehelper::t10, MPointer, true>,
|
|
mdistRange2VMT<mtreehelper::t11, MPointer, true>,
|
|
mdistRange2VMT<mtreehelper::t12, MPointer, true>
|
|
};
|
|
|
|
OperatorSpec mdistRange2Spec(
|
|
"MTREE x DATA x real -> stream(tuple((TID tid))), "
|
|
"MTREE represented as a mem or mpointer ",
|
|
"mem_mtree mdistRange2[keyAttr, maxDist] ",
|
|
"Retrieves those tuple ids from an mtree those key value has "
|
|
"a maximum distaance of the given dist",
|
|
"query mkinos_mtree mdistRange2[ alexanderplatz , 2000.0] count"
|
|
);
|
|
|
|
Operator mdistRange2Op(
|
|
"mdistRange2",
|
|
mdistRange2Spec.getStr(),
|
|
24,
|
|
mdistRange2VM,
|
|
mdistRange2Select,
|
|
mdistRange2TM<true>
|
|
);
|
|
|
|
|
|
/*
|
|
Operator ~mdistScan2~
|
|
|
|
This operator creates a stream of TupleIDs
|
|
whose associated objects are in increasing order
|
|
to the reference object.
|
|
|
|
*/
|
|
template<bool wrap>
|
|
ListExpr mdistScan2TM(ListExpr args){
|
|
string err = "MTREE x T expected";
|
|
if(!nl->HasLength(args,2)){
|
|
return listutils::typeError(err + " ( wrong number of args)");
|
|
}
|
|
ListExpr a1 = nl->First(args);
|
|
ListExpr a2 = nl->Second(args);
|
|
if(MPointer::checkType(a1)){
|
|
a1 = nl->Second(a1);
|
|
}
|
|
if(!Mem::checkType(a1)){
|
|
return listutils::typeError("1st arg is not a memory object");
|
|
}
|
|
a1 = nl->Second(a1); // remove mem
|
|
if(!mtreehelper::checkType(a1,a2)){
|
|
return listutils::typeError(err+ "( first arg is not an "
|
|
"mtree over key type)");
|
|
}
|
|
if(!wrap){
|
|
return nl->TwoElemList(
|
|
listutils::basicSymbol<Stream<TupleIdentifier> >(),
|
|
listutils::basicSymbol<TupleIdentifier>());
|
|
} else {
|
|
ListExpr attrList = nl->OneElemList(
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom("TID"),
|
|
listutils::basicSymbol<TupleIdentifier>()));
|
|
return nl->TwoElemList(
|
|
listutils::basicSymbol<Stream<Tuple> >(),
|
|
nl->TwoElemList(
|
|
listutils::basicSymbol<Tuple>(),
|
|
attrList));
|
|
}
|
|
}
|
|
|
|
template<class T>
|
|
struct mdistScan2Info{
|
|
NNIterator<MTreeEntry<T>, StdDistComp<T> >* it;
|
|
// NNIterator<pair<T,TupleId>, StdDistComp<T>,
|
|
// MemCloner<pair<T,TupleId> > >* it;
|
|
TupleType* tt;
|
|
};
|
|
|
|
|
|
template <class T, class N, bool wrap>
|
|
int mdistScan2VMT (Word* args, Word& result, int message,
|
|
Word& local, Supplier s) {
|
|
mdistScan2Info<T>* li = (mdistScan2Info<T>*) local.addr;
|
|
int noDistFunCalls = 0;
|
|
switch(message){
|
|
case OPEN: {
|
|
if(li) {
|
|
delete li->it;
|
|
if(li->tt){
|
|
li->tt->DeleteIfAllowed();
|
|
}
|
|
delete li;
|
|
local.addr = 0;
|
|
}
|
|
T* attr = (T*) args[1].addr;
|
|
N* Name = (N*) args[0].addr;
|
|
typedef MemoryMtreeObject<T,StdDistComp<T> > mtot;
|
|
mtot* tree = getMtree<N,T>(Name);
|
|
if(!tree){
|
|
return 0;
|
|
}
|
|
MMMTree<MTreeEntry<T>, StdDistComp<T> >* mtree = tree->getmtree();
|
|
// MMMTree<pair<T, TupleId>,StdDistComp<T>,
|
|
// MemCloner<pair<T, TupleId>> >* mtree =
|
|
// tree->getmtree();
|
|
if(mtree){
|
|
MTreeEntry<T> p(*attr, 0);
|
|
// pair<T,TupleId> p(*attr,0);
|
|
li = new mdistScan2Info<T>();
|
|
li->it = mtree->nnSearch(p);
|
|
if(!wrap){
|
|
li->tt=0;
|
|
} else {
|
|
li->tt = new TupleType(nl->Second(GetTupleResultType(s)));
|
|
}
|
|
local.addr = li;
|
|
}
|
|
return 0;
|
|
}
|
|
case REQUEST: {
|
|
if(!li){
|
|
result.addr=0;
|
|
return CANCEL;
|
|
}
|
|
const MTreeEntry<T>* n = li->it->next();
|
|
TupleIdentifier* tid = n ?
|
|
new TupleIdentifier(true, n->getTid()) : 0;
|
|
// const pair<T,TupleId>* n = li->it->next();
|
|
// TupleIdentifier* tid = n? new TupleIdentifier(true,n->second):0;
|
|
if(!tid){
|
|
result.addr=0;
|
|
return CANCEL;
|
|
}
|
|
if(!wrap){
|
|
result.addr = tid;
|
|
} else {
|
|
Tuple* tuple = new Tuple(li->tt);
|
|
tuple->PutAttribute(0,tid);
|
|
result.addr = tuple;
|
|
}
|
|
|
|
return result.addr?YIELD:CANCEL;
|
|
}
|
|
case CLOSE:
|
|
cout << "Number of distance function calls: " << noDistFunCalls
|
|
<< endl;
|
|
if(li){
|
|
delete li->it;
|
|
if(li->tt){
|
|
li->tt->DeleteIfAllowed();
|
|
}
|
|
delete li;
|
|
local.addr = 0;
|
|
}
|
|
return 0;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
6.3 Selection and Value Mapping Array
|
|
|
|
*/
|
|
int mdistScan2Select(ListExpr args){
|
|
ListExpr type = nl->Second(args);
|
|
int n;
|
|
int m = 12;
|
|
if(Mem::checkType(nl->First(args))){
|
|
n = 0;
|
|
} else { // mpointer
|
|
n = m;
|
|
}
|
|
return mtreehelper::getTypeNo(type,m) + n;
|
|
}
|
|
|
|
// note: if adding attributes with flobs, the value mapping must be changed
|
|
|
|
ValueMapping mdistScan2VM[] = {
|
|
mdistScan2VMT<mtreehelper::t1, Mem, true>,
|
|
mdistScan2VMT<mtreehelper::t2, Mem, true>,
|
|
mdistScan2VMT<mtreehelper::t3, Mem, true>,
|
|
mdistScan2VMT<mtreehelper::t4, Mem, true>,
|
|
mdistScan2VMT<mtreehelper::t5, Mem, true>,
|
|
mdistScan2VMT<mtreehelper::t6, Mem, true>,
|
|
mdistScan2VMT<mtreehelper::t7, Mem, true>,
|
|
mdistScan2VMT<mtreehelper::t8, Mem, true>,
|
|
mdistScan2VMT<mtreehelper::t9, Mem, true>,
|
|
mdistScan2VMT<mtreehelper::t10, Mem, true>,
|
|
mdistScan2VMT<mtreehelper::t11, Mem, true>,
|
|
mdistScan2VMT<mtreehelper::t12, Mem, true>,
|
|
|
|
mdistScan2VMT<mtreehelper::t1, MPointer, true>,
|
|
mdistScan2VMT<mtreehelper::t2, MPointer, true>,
|
|
mdistScan2VMT<mtreehelper::t3, MPointer, true>,
|
|
mdistScan2VMT<mtreehelper::t4, MPointer, true>,
|
|
mdistScan2VMT<mtreehelper::t5, MPointer, true>,
|
|
mdistScan2VMT<mtreehelper::t6, MPointer, true>,
|
|
mdistScan2VMT<mtreehelper::t7, MPointer, true>,
|
|
mdistScan2VMT<mtreehelper::t8, MPointer, true>,
|
|
mdistScan2VMT<mtreehelper::t9, MPointer, true>,
|
|
mdistScan2VMT<mtreehelper::t10, MPointer, true>,
|
|
mdistScan2VMT<mtreehelper::t11, MPointer, true>,
|
|
mdistScan2VMT<mtreehelper::t12, MPointer, true>
|
|
};
|
|
|
|
OperatorSpec mdistScan2Spec(
|
|
"MTREE x DATA -> stream(tuple((TID tid))), "
|
|
"MTREE represented as string, me, or mpointer ",
|
|
"mem_mtree mdistScan2[keyAttr] ",
|
|
"Scans the tuple ids within an m-tree in increasing "
|
|
"distance of the reference object to the associated "
|
|
"objects.",
|
|
"query mkinos_mtree mdistScan2[ alexanderplatz] count"
|
|
);
|
|
|
|
Operator mdistScan2Op(
|
|
"mdistScan2",
|
|
mdistScan2Spec.getStr(),
|
|
36,
|
|
mdistScan2VM,
|
|
mdistScan2Select,
|
|
mdistScan2TM<true>
|
|
);
|
|
|
|
|
|
/*
|
|
Operator mdistRange
|
|
|
|
*/
|
|
ListExpr mdistRangeTM(ListExpr args) {
|
|
string err = "MTREE(T) x MREL x T (x U) x real expected";
|
|
if (!nl->HasLength(args,4) && !nl->HasLength(args, 5)) {
|
|
return listutils::typeError(err + " (wrong number of args)");
|
|
}
|
|
ListExpr a1 = nl->First(args);
|
|
ListExpr a2 = nl->Second(args);
|
|
if (MPointer::checkType(a1)) {
|
|
a1 = nl->Second(a1);
|
|
}
|
|
if (!Mem::checkType(a1)) {
|
|
return listutils::typeError("first arg is not a memory object");
|
|
}
|
|
if (MPointer::checkType(a2)) {
|
|
a2 = nl->Second(a2);
|
|
}
|
|
if (!Mem::checkType(a2)) {
|
|
return listutils::typeError("2nd arg is not a memory object");
|
|
}
|
|
a1 = nl->Second(a1);
|
|
a2 = nl->Second(a2);
|
|
if (!Relation::checkType(a2)) {
|
|
return listutils::typeError("second arg is not a relation");
|
|
}
|
|
ListExpr a3 = nl->Third(args);
|
|
ListExpr a4 = nl->Fourth(args);
|
|
if (nl->HasLength(args, 4)) {
|
|
if (!mtreehelper::checkType(a1, a3)) {
|
|
return listutils::typeError("first arg is not a mtree over "
|
|
+ nl->ToString(a3));
|
|
}
|
|
}
|
|
else {
|
|
if (!mtreehelper::checkType(a1, nl->SymbolAtom(Tuple::BasicType()))) {
|
|
return listutils::typeError("first arg is not a mtree over tuples");
|
|
}
|
|
if (!temporalalgebra::MPoint::checkType(a3) &&
|
|
!temporalalgebra::CUPoint::checkType(a3) &&
|
|
!temporalalgebra::CMPoint::checkType(a3)) {
|
|
return listutils::typeError("third arg is not a (m|cu|cm)point");
|
|
}
|
|
if (!stj::isSymbolicType(a4)) {
|
|
return listutils::typeError("fourth arg is not an mlabel(s) / mplace(s)");
|
|
}
|
|
a4 = nl->Fifth(args);
|
|
}
|
|
if (!CcReal::checkType(a4)) {
|
|
return listutils::typeError(err + "final arg is not a real");
|
|
}
|
|
return nl->TwoElemList(
|
|
listutils::basicSymbol<Stream<Tuple> >(),
|
|
nl->Second(a2));
|
|
}
|
|
|
|
template<class T, class Dist>
|
|
class distRangeInfo{
|
|
public:
|
|
|
|
distRangeInfo( MemoryMtreeObject<T, Dist>* mtree,
|
|
MemoryRelObject* mrel,
|
|
T* ref,
|
|
double dist){
|
|
|
|
rel = mrel->getmmrel();
|
|
MTreeEntry<T> p(*ref, 0);
|
|
// pair<T,TupleId> p(*ref,0);
|
|
it = mtree->getmtree()->rangeSearch(p, dist);
|
|
}
|
|
|
|
~distRangeInfo() {
|
|
delete it;
|
|
}
|
|
|
|
Tuple* next() {
|
|
while(true) {
|
|
const MTreeEntry<T>* p = it->next();
|
|
// const pair<T,TupleId>* p = it->next();
|
|
if(!p) {
|
|
return 0;
|
|
}
|
|
if (p->getTid() <= rel->size()) {
|
|
Tuple* res = (*rel)[p->getTid() - 1];
|
|
if(res) { // ignore deleted tuples
|
|
res->IncReference();
|
|
return res;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
size_t getNoDistFunCalls() {
|
|
return it->getNoDistFunCalls();
|
|
}
|
|
|
|
|
|
private:
|
|
vector<Tuple*>* rel;
|
|
RangeIterator<MTreeEntry<T>, Dist>* it;
|
|
// RangeIterator<pair<T,TupleId> , StdDistComp<T>,
|
|
// MemCloner<pair<T,TupleId> > >* it;
|
|
|
|
};
|
|
|
|
template<class K, class T, class R>
|
|
int mdistRangeVMT (Word* args, Word& result, int message, Word& local,
|
|
Supplier s) {
|
|
distRangeInfo<K, StdDistComp<K> >* li =
|
|
(distRangeInfo<K, StdDistComp<K> >*) local.addr;
|
|
switch (message) {
|
|
case OPEN : {
|
|
if (li) {
|
|
delete li;
|
|
local.addr = 0;
|
|
}
|
|
R* relN = (R*)args[1].addr;
|
|
MemoryRelObject* rel = getMemRel(relN, nl->Second(qp->GetType(s)));
|
|
if (!rel) {
|
|
return 0;
|
|
}
|
|
CcReal* dist = (CcReal*)args[3].addr;
|
|
if (!dist->IsDefined()) {
|
|
return 0;
|
|
}
|
|
double d = dist->GetValue();
|
|
if (d < 0) {
|
|
return 0;
|
|
}
|
|
T* treeN = (T*)args[0].addr;
|
|
MemoryMtreeObject<K, StdDistComp<K> >* m = getMtree<T, K>(treeN);
|
|
if (!m) {
|
|
return 0;
|
|
}
|
|
K* key = (K*)args[2].addr;
|
|
local.addr = new distRangeInfo<K, StdDistComp<K> >(m, rel, key, d);
|
|
return 0;
|
|
}
|
|
case REQUEST: {
|
|
result.addr = li ? li->next() : 0;
|
|
return result.addr ? YIELD : CANCEL;
|
|
}
|
|
case CLOSE : {
|
|
if (li) {
|
|
mtreehelper::increaseCounter("counterMDistRange",
|
|
li->getNoDistFunCalls());
|
|
delete li;
|
|
local.addr = 0;
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
template<class K, class L, class T, class R>
|
|
int mdistRangeVMT2(Word* args, Word& result, int message, Word& local,
|
|
Supplier s) {
|
|
distRangeInfo<pair<K, L>, StdDistCompExt<K, L> >* li =
|
|
(distRangeInfo<pair<K, L>, StdDistCompExt<K, L> >*) local.addr;
|
|
switch (message) {
|
|
case OPEN : {
|
|
if (li) {
|
|
delete li;
|
|
local.addr = 0;
|
|
}
|
|
R* relN = (R*)args[1].addr;
|
|
MemoryRelObject* rel = getMemRel(relN, nl->Second(qp->GetType(s)));
|
|
if (!rel) {
|
|
return 0;
|
|
}
|
|
CcReal* dist = (CcReal*)args[4].addr;
|
|
if (!dist->IsDefined()) {
|
|
return 0;
|
|
}
|
|
double d = dist->GetValue();
|
|
if (d < 0) {
|
|
return 0;
|
|
}
|
|
T* treeN = (T*)args[0].addr;
|
|
MemoryMtreeObject<pair<K, L>, StdDistCompExt<K, L> >* m =
|
|
getMtree<T, K, L >(treeN);
|
|
if (!m) {
|
|
return 0;
|
|
}
|
|
K* key1 = (K*)args[2].addr;
|
|
L* key2 = (L*)args[3].addr;
|
|
pair<K, L> key(*key1, *key2);
|
|
local.addr = new distRangeInfo<pair<K, L>, StdDistCompExt<K, L> >(m, rel,
|
|
&key, d);
|
|
return 0;
|
|
}
|
|
case REQUEST: {
|
|
result.addr = li ? li->next() : 0;
|
|
return result.addr ? YIELD : CANCEL;
|
|
}
|
|
case CLOSE : {
|
|
if (li) {
|
|
mtreehelper::increaseCounter("counterMDistRange",
|
|
li->getNoDistFunCalls());
|
|
delete li;
|
|
local.addr = 0;
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
template<int minNoArgs>
|
|
int mdistRangeScanSelect(ListExpr args){
|
|
int o1 = -1;
|
|
int o2 = -1;
|
|
ListExpr a1 = nl->First(args);
|
|
ListExpr a2 = nl->Second(args);
|
|
if (nl->HasLength(args, minNoArgs)) {
|
|
ListExpr typeL = nl->Third(args);
|
|
int type = mtreehelper::getTypeNo(typeL,12);
|
|
|
|
if(Mem::checkType(a1)) o1=0;
|
|
if(MPointer::checkType(a1)) o1=24;
|
|
if(o1<0) return -1;
|
|
|
|
if(Mem::checkType(a2)) o2=0;
|
|
if(MPointer::checkType(a2)) o2=12;
|
|
if(o2<0) return -1;
|
|
|
|
int res = type + o1 + o2;
|
|
return res;
|
|
}
|
|
else {
|
|
ListExpr typeList1 = nl->Third(args);
|
|
ListExpr typeList2 = nl->Fourth(args);
|
|
int type1 = mtreehelper::getTypeNo(typeList1, 12) - 9;
|
|
int type2 = stj::getTypeNo(typeList2);
|
|
if (Mem::checkType(a1)) {
|
|
o1 = 48;
|
|
}
|
|
if (MPointer::checkType(a1)) {
|
|
o1 = 72;
|
|
}
|
|
if (o1 < 0) {
|
|
return -1;
|
|
}
|
|
|
|
if (Mem::checkType(a2)) {
|
|
o2 = 0;
|
|
}
|
|
if (MPointer::checkType(a2)) {
|
|
o2 = 12;
|
|
}
|
|
if (o2 < 0) {
|
|
return -1;
|
|
}
|
|
int res = type1 + 3 * type2 + o1 + o2;
|
|
return res;
|
|
}
|
|
|
|
}
|
|
|
|
// note: if adding attributes with flobs, the value mapping must be changed
|
|
|
|
ValueMapping mdistRangeVM[] = {
|
|
mdistRangeVMT<mtreehelper::t1,Mem,Mem>,
|
|
mdistRangeVMT<mtreehelper::t2,Mem,Mem>,
|
|
mdistRangeVMT<mtreehelper::t3,Mem,Mem>,
|
|
mdistRangeVMT<mtreehelper::t4,Mem,Mem>,
|
|
mdistRangeVMT<mtreehelper::t5,Mem,Mem>,
|
|
mdistRangeVMT<mtreehelper::t6,Mem,Mem>,
|
|
mdistRangeVMT<mtreehelper::t7,Mem,Mem>,
|
|
mdistRangeVMT<mtreehelper::t8,Mem,Mem>,
|
|
mdistRangeVMT<mtreehelper::t9,Mem,Mem>,
|
|
mdistRangeVMT<mtreehelper::t10,Mem,Mem>,
|
|
mdistRangeVMT<mtreehelper::t11,Mem,Mem>,
|
|
mdistRangeVMT<mtreehelper::t12,Mem,Mem>,
|
|
|
|
mdistRangeVMT<mtreehelper::t1,Mem,MPointer>,
|
|
mdistRangeVMT<mtreehelper::t2,Mem,MPointer>,
|
|
mdistRangeVMT<mtreehelper::t3,Mem,MPointer>,
|
|
mdistRangeVMT<mtreehelper::t4,Mem,MPointer>,
|
|
mdistRangeVMT<mtreehelper::t5,Mem,MPointer>,
|
|
mdistRangeVMT<mtreehelper::t6,Mem,MPointer>,
|
|
mdistRangeVMT<mtreehelper::t7,Mem,MPointer>,
|
|
mdistRangeVMT<mtreehelper::t8,Mem,MPointer>,
|
|
mdistRangeVMT<mtreehelper::t9,Mem,MPointer>,
|
|
mdistRangeVMT<mtreehelper::t10,Mem,MPointer>,
|
|
mdistRangeVMT<mtreehelper::t11,Mem,MPointer>,
|
|
mdistRangeVMT<mtreehelper::t12,Mem,MPointer>,
|
|
|
|
mdistRangeVMT<mtreehelper::t1,MPointer,Mem>,
|
|
mdistRangeVMT<mtreehelper::t2,MPointer,Mem>,
|
|
mdistRangeVMT<mtreehelper::t3,MPointer,Mem>,
|
|
mdistRangeVMT<mtreehelper::t4,MPointer,Mem>,
|
|
mdistRangeVMT<mtreehelper::t5,MPointer,Mem>,
|
|
mdistRangeVMT<mtreehelper::t6,MPointer,Mem>,
|
|
mdistRangeVMT<mtreehelper::t7,MPointer,Mem>,
|
|
mdistRangeVMT<mtreehelper::t8,MPointer,Mem>,
|
|
mdistRangeVMT<mtreehelper::t9,MPointer,Mem>,
|
|
mdistRangeVMT<mtreehelper::t10,MPointer,Mem>,
|
|
mdistRangeVMT<mtreehelper::t11,MPointer,Mem>,
|
|
mdistRangeVMT<mtreehelper::t12,MPointer,Mem>,
|
|
|
|
mdistRangeVMT<mtreehelper::t1,MPointer,MPointer>,
|
|
mdistRangeVMT<mtreehelper::t2,MPointer,MPointer>,
|
|
mdistRangeVMT<mtreehelper::t3,MPointer,MPointer>,
|
|
mdistRangeVMT<mtreehelper::t4,MPointer,MPointer>,
|
|
mdistRangeVMT<mtreehelper::t5,MPointer,MPointer>,
|
|
mdistRangeVMT<mtreehelper::t6,MPointer,MPointer>,
|
|
mdistRangeVMT<mtreehelper::t7,MPointer,MPointer>,
|
|
mdistRangeVMT<mtreehelper::t8,MPointer,MPointer>,
|
|
mdistRangeVMT<mtreehelper::t9,MPointer,MPointer>,
|
|
mdistRangeVMT<mtreehelper::t10,MPointer,MPointer>,
|
|
mdistRangeVMT<mtreehelper::t11,MPointer,MPointer>,
|
|
mdistRangeVMT<mtreehelper::t12,MPointer,MPointer>,
|
|
|
|
mdistRangeVMT2<temporalalgebra::MPoint, stj::MLabel, Mem, Mem>,
|
|
mdistRangeVMT2<temporalalgebra::CUPoint, stj::MLabel, Mem, Mem>,
|
|
mdistRangeVMT2<temporalalgebra::CMPoint, stj::MLabel, Mem, Mem>,
|
|
mdistRangeVMT2<temporalalgebra::MPoint, stj::MLabels, Mem, Mem>,
|
|
mdistRangeVMT2<temporalalgebra::CUPoint, stj::MLabels, Mem, Mem>,
|
|
mdistRangeVMT2<temporalalgebra::CMPoint, stj::MLabels, Mem, Mem>,
|
|
mdistRangeVMT2<temporalalgebra::MPoint, stj::MPlace, Mem, Mem>,
|
|
mdistRangeVMT2<temporalalgebra::CUPoint, stj::MPlace, Mem, Mem>,
|
|
mdistRangeVMT2<temporalalgebra::CMPoint, stj::MPlace, Mem, Mem>,
|
|
mdistRangeVMT2<temporalalgebra::MPoint, stj::MPlaces, Mem, Mem>,
|
|
mdistRangeVMT2<temporalalgebra::CUPoint, stj::MPlaces, Mem, Mem>,
|
|
mdistRangeVMT2<temporalalgebra::CMPoint, stj::MPlaces, Mem, Mem>,
|
|
|
|
mdistRangeVMT2<temporalalgebra::MPoint, stj::MLabel, Mem, MPointer>,
|
|
mdistRangeVMT2<temporalalgebra::CUPoint, stj::MLabel, Mem, MPointer>,
|
|
mdistRangeVMT2<temporalalgebra::CMPoint, stj::MLabel, Mem, MPointer>,
|
|
mdistRangeVMT2<temporalalgebra::MPoint, stj::MLabels, Mem, MPointer>,
|
|
mdistRangeVMT2<temporalalgebra::CUPoint, stj::MLabels, Mem, MPointer>,
|
|
mdistRangeVMT2<temporalalgebra::CMPoint, stj::MLabels, Mem, MPointer>,
|
|
mdistRangeVMT2<temporalalgebra::MPoint, stj::MPlace, Mem, MPointer>,
|
|
mdistRangeVMT2<temporalalgebra::CUPoint, stj::MPlace, Mem, MPointer>,
|
|
mdistRangeVMT2<temporalalgebra::CMPoint, stj::MPlace, Mem, MPointer>,
|
|
mdistRangeVMT2<temporalalgebra::MPoint, stj::MPlaces, Mem, MPointer>,
|
|
mdistRangeVMT2<temporalalgebra::CUPoint, stj::MPlaces, Mem, MPointer>,
|
|
mdistRangeVMT2<temporalalgebra::CMPoint, stj::MPlaces, Mem, MPointer>,
|
|
|
|
mdistRangeVMT2<temporalalgebra::MPoint, stj::MLabel, MPointer, Mem>,
|
|
mdistRangeVMT2<temporalalgebra::CUPoint, stj::MLabel, MPointer, Mem>,
|
|
mdistRangeVMT2<temporalalgebra::CMPoint, stj::MLabel, MPointer, Mem>,
|
|
mdistRangeVMT2<temporalalgebra::MPoint, stj::MLabels, MPointer, Mem>,
|
|
mdistRangeVMT2<temporalalgebra::CUPoint, stj::MLabels, MPointer, Mem>,
|
|
mdistRangeVMT2<temporalalgebra::CMPoint, stj::MLabels, MPointer, Mem>,
|
|
mdistRangeVMT2<temporalalgebra::MPoint, stj::MPlace, MPointer, Mem>,
|
|
mdistRangeVMT2<temporalalgebra::CUPoint, stj::MPlace, MPointer, Mem>,
|
|
mdistRangeVMT2<temporalalgebra::CMPoint, stj::MPlace, MPointer, Mem>,
|
|
mdistRangeVMT2<temporalalgebra::MPoint, stj::MPlaces, MPointer, Mem>,
|
|
mdistRangeVMT2<temporalalgebra::CUPoint, stj::MPlaces, MPointer, Mem>,
|
|
mdistRangeVMT2<temporalalgebra::CMPoint, stj::MPlaces, MPointer, Mem>,
|
|
|
|
mdistRangeVMT2<temporalalgebra::MPoint, stj::MLabel, MPointer, MPointer>,
|
|
mdistRangeVMT2<temporalalgebra::CUPoint, stj::MLabel, MPointer, MPointer>,
|
|
mdistRangeVMT2<temporalalgebra::CMPoint, stj::MLabel, MPointer, MPointer>,
|
|
mdistRangeVMT2<temporalalgebra::MPoint, stj::MLabels, MPointer, MPointer>,
|
|
mdistRangeVMT2<temporalalgebra::CUPoint, stj::MLabels, MPointer, MPointer>,
|
|
mdistRangeVMT2<temporalalgebra::CMPoint, stj::MLabels, MPointer, MPointer>,
|
|
mdistRangeVMT2<temporalalgebra::MPoint, stj::MPlace, MPointer, MPointer>,
|
|
mdistRangeVMT2<temporalalgebra::CUPoint, stj::MPlace, MPointer, MPointer>,
|
|
mdistRangeVMT2<temporalalgebra::CMPoint, stj::MPlace, MPointer, MPointer>,
|
|
mdistRangeVMT2<temporalalgebra::MPoint, stj::MPlaces, MPointer, MPointer>,
|
|
mdistRangeVMT2<temporalalgebra::CUPoint, stj::MPlaces, MPointer, MPointer>,
|
|
mdistRangeVMT2<temporalalgebra::CMPoint, stj::MPlaces, MPointer, MPointer>
|
|
};
|
|
|
|
OperatorSpec mdistRangeSpec(
|
|
"MTREE x MREL x T (x U) x real -> stream(tuple) , MTREE, "
|
|
"MREL represented as string, mem, or mpointer",
|
|
"mem_mtree mem_rel mdistRange[keyAttr, maxDist] ",
|
|
"Retrieves those tuples from a memory relation "
|
|
"having a distance smaller or equals to a given dist "
|
|
"to a key value (or pair of key values). This operation is aided by a memory "
|
|
"based m-tree.",
|
|
"query mkinos_mtree mKinos mdistRange[ alexanderplatz , 2000.0] count"
|
|
);
|
|
|
|
Operator mdistRangeOp(
|
|
"mdistRange",
|
|
mdistRangeSpec.getStr(),
|
|
96,
|
|
mdistRangeVM,
|
|
mdistRangeScanSelect<4>,
|
|
mdistRangeTM
|
|
);
|
|
|
|
/*
|
|
Operator ~mdistRangeN~
|
|
|
|
*/
|
|
ListExpr mdistRangeNTM(ListExpr args) {
|
|
string err = "NTREE(T) x MREL x T (x U) x real expected";
|
|
if (!nl->HasLength(args, 4) && !nl->HasLength(args, 5)) {
|
|
return listutils::typeError(err + " (wrong number of args)");
|
|
}
|
|
ListExpr a1 = nl->First(args);
|
|
ListExpr a2 = nl->Second(args);
|
|
if (MPointer::checkType(a1)) {
|
|
a1 = nl->Second(a1);
|
|
}
|
|
if (!Mem::checkType(a1)) {
|
|
return listutils::typeError("first arg is not a memory object");
|
|
}
|
|
if (MPointer::checkType(a2)) {
|
|
a2 = nl->Second(a2);
|
|
}
|
|
if (!Mem::checkType(a2)) {
|
|
return listutils::typeError("2nd arg is not a memory object");
|
|
}
|
|
a1 = nl->Second(a1);
|
|
a2 = nl->Second(a2);
|
|
if (!Relation::checkType(a2)) {
|
|
return listutils::typeError("second arg is not a relation");
|
|
}
|
|
ListExpr a3 = nl->Third(args);
|
|
ListExpr a4 = nl->Fourth(args);
|
|
if (nl->HasLength(args, 4)) {
|
|
if (!mtreehelper::checkTypeN(a1, a3)) {
|
|
return listutils::typeError("first arg is not an ntree over "
|
|
+ nl->ToString(a3));
|
|
}
|
|
}
|
|
else {
|
|
if (!mtreehelper::checkType(a1, nl->SymbolAtom(Tuple::BasicType()))) {
|
|
return listutils::typeError("first arg is not an ntree over tuples");
|
|
}
|
|
if (!temporalalgebra::MPoint::checkType(a3) &&
|
|
!temporalalgebra::CUPoint::checkType(a3) &&
|
|
!temporalalgebra::CMPoint::checkType(a3)) {
|
|
return listutils::typeError("third arg is not a (m|cu|cm)point");
|
|
}
|
|
if (!stj::isSymbolicType(a4)) {
|
|
return listutils::typeError("fourth arg is not an mlabel(s) / mplace(s)");
|
|
}
|
|
a4 = nl->Fifth(args);
|
|
}
|
|
if (!CcReal::checkType(a4)) {
|
|
return listutils::typeError(err + "final arg is not a real");
|
|
}
|
|
return nl->TwoElemList(
|
|
listutils::basicSymbol<Stream<Tuple> >(),
|
|
nl->Second(a2));
|
|
}
|
|
|
|
template<class T, class Dist>
|
|
class distRangeNInfo {
|
|
public:
|
|
distRangeNInfo(MemoryNtreeObject<T, Dist>* ntree, MemoryRelObject* mrel,
|
|
T* ref, double dist) {
|
|
rel = mrel->getmmrel();
|
|
MTreeEntry<T> p(*ref, 0);
|
|
it = ntree->getntree()->rangeSearch(p, dist);
|
|
}
|
|
|
|
~distRangeNInfo() {
|
|
delete it;
|
|
}
|
|
|
|
Tuple* next() {
|
|
while (true) {
|
|
const TupleId tid = it->next();
|
|
if ((int)tid == -1) {
|
|
return 0;
|
|
}
|
|
if (tid <= rel->size()) {
|
|
Tuple* res = (*rel)[tid - 1];
|
|
if (res) { // ignore deleted tuples
|
|
res->IncReference();
|
|
return res;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
size_t getNoDistFunCalls() {
|
|
return it->getNoDistFunCalls();
|
|
}
|
|
|
|
private:
|
|
vector<Tuple*>* rel;
|
|
RangeIteratorN<MTreeEntry<T>, Dist>* it;
|
|
};
|
|
|
|
template<class K, class T, class R>
|
|
int mdistRangeNVMT(Word* args, Word& result, int message, Word& local,
|
|
Supplier s) {
|
|
distRangeNInfo<K, StdDistComp<K> >* li =
|
|
(distRangeNInfo<K, StdDistComp<K> >*)local.addr;
|
|
switch (message) {
|
|
case OPEN : {
|
|
if (li) {
|
|
delete li;
|
|
local.addr = 0;
|
|
}
|
|
R* relN = (R*)args[1].addr;
|
|
MemoryRelObject* rel = getMemRel(relN, nl->Second(qp->GetType(s)));
|
|
if (!rel) {
|
|
return 0;
|
|
}
|
|
CcReal* dist = (CcReal*)args[3].addr;
|
|
if (!dist->IsDefined()) {
|
|
return 0;
|
|
}
|
|
double d = dist->GetValue();
|
|
if (d < 0) {
|
|
return 0;
|
|
}
|
|
T* treeN = (T*)args[0].addr;
|
|
MemoryNtreeObject<K, StdDistComp<K> >* n = getNtree<T, K>(treeN);
|
|
if (!n) {
|
|
return 0;
|
|
}
|
|
K* key = (K*)args[2].addr;
|
|
local.addr = new distRangeNInfo<K, StdDistComp<K> >(n, rel, key, d);
|
|
return 0;
|
|
}
|
|
case REQUEST: {
|
|
result.addr = li ? li->next() : 0;
|
|
return result.addr ? YIELD : CANCEL;
|
|
}
|
|
case CLOSE : {
|
|
if (li) {
|
|
mtreehelper::increaseCounter("counterMDistRangeN",
|
|
li->getNoDistFunCalls());
|
|
delete li;
|
|
local.addr = 0;
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int mdistRangeNSelect(ListExpr args) {
|
|
int o1 = -1;
|
|
int o2 = -1;
|
|
ListExpr a1 = nl->First(args);
|
|
ListExpr a2 = nl->Second(args);
|
|
if (nl->HasLength(args, 4)) {
|
|
ListExpr typeL = nl->Third(args);
|
|
int type = mtreehelper::getTypeNo(typeL,12);
|
|
if(Mem::checkType(a1)) o1=0;
|
|
if(MPointer::checkType(a1)) o1=24;
|
|
if(o1<0) return -1;
|
|
|
|
if(Mem::checkType(a2)) o2=0;
|
|
if(MPointer::checkType(a2)) o2=12;
|
|
if(o2<0) return -1;
|
|
|
|
int res = type + o1 + o2;
|
|
return res;
|
|
}
|
|
return -1;
|
|
// else { TODO!
|
|
// ListExpr typeList1 = nl->Third(args);
|
|
// ListExpr typeList2 = nl->Fourth(args);
|
|
// int type1 = mtreehelper::getTypeNo(typeList1, 12) - 9;
|
|
// int type2 = stj::getTypeNo(typeList2);
|
|
// if (Mem::checkType(a1)) {
|
|
// o1 = 48;
|
|
// }
|
|
// if (MPointer::checkType(a1)) {
|
|
// o1 = 72;
|
|
// }
|
|
// if (o1 < 0) {
|
|
// return -1;
|
|
// }
|
|
//
|
|
// if (Mem::checkType(a2)) {
|
|
// o2 = 0;
|
|
// }
|
|
// if (MPointer::checkType(a2)) {
|
|
// o2 = 12;
|
|
// }
|
|
// if (o2 < 0) {
|
|
// return -1;
|
|
// }
|
|
// int res = type1 + 3 * type2 + o1 + o2;
|
|
// return res;
|
|
// }
|
|
}
|
|
|
|
ValueMapping mdistRangeNVM[] = {
|
|
mdistRangeNVMT<mtreehelper::t1,Mem,Mem>,
|
|
mdistRangeNVMT<mtreehelper::t2,Mem,Mem>,
|
|
mdistRangeNVMT<mtreehelper::t3,Mem,Mem>,
|
|
mdistRangeNVMT<mtreehelper::t4,Mem,Mem>,
|
|
mdistRangeNVMT<mtreehelper::t5,Mem,Mem>,
|
|
mdistRangeNVMT<mtreehelper::t6,Mem,Mem>,
|
|
mdistRangeNVMT<mtreehelper::t7,Mem,Mem>,
|
|
mdistRangeNVMT<mtreehelper::t8,Mem,Mem>,
|
|
mdistRangeNVMT<mtreehelper::t9,Mem,Mem>,
|
|
mdistRangeNVMT<mtreehelper::t10,Mem,Mem>,
|
|
mdistRangeNVMT<mtreehelper::t11,Mem,Mem>,
|
|
mdistRangeNVMT<mtreehelper::t12,Mem,Mem>,
|
|
|
|
mdistRangeNVMT<mtreehelper::t1,Mem,MPointer>,
|
|
mdistRangeNVMT<mtreehelper::t2,Mem,MPointer>,
|
|
mdistRangeNVMT<mtreehelper::t3,Mem,MPointer>,
|
|
mdistRangeNVMT<mtreehelper::t4,Mem,MPointer>,
|
|
mdistRangeNVMT<mtreehelper::t5,Mem,MPointer>,
|
|
mdistRangeNVMT<mtreehelper::t6,Mem,MPointer>,
|
|
mdistRangeNVMT<mtreehelper::t7,Mem,MPointer>,
|
|
mdistRangeNVMT<mtreehelper::t8,Mem,MPointer>,
|
|
mdistRangeNVMT<mtreehelper::t9,Mem,MPointer>,
|
|
mdistRangeNVMT<mtreehelper::t10,Mem,MPointer>,
|
|
mdistRangeNVMT<mtreehelper::t11,Mem,MPointer>,
|
|
mdistRangeNVMT<mtreehelper::t12,Mem,MPointer>,
|
|
|
|
mdistRangeNVMT<mtreehelper::t1,MPointer,Mem>,
|
|
mdistRangeNVMT<mtreehelper::t2,MPointer,Mem>,
|
|
mdistRangeNVMT<mtreehelper::t3,MPointer,Mem>,
|
|
mdistRangeNVMT<mtreehelper::t4,MPointer,Mem>,
|
|
mdistRangeNVMT<mtreehelper::t5,MPointer,Mem>,
|
|
mdistRangeNVMT<mtreehelper::t6,MPointer,Mem>,
|
|
mdistRangeNVMT<mtreehelper::t7,MPointer,Mem>,
|
|
mdistRangeNVMT<mtreehelper::t8,MPointer,Mem>,
|
|
mdistRangeNVMT<mtreehelper::t9,MPointer,Mem>,
|
|
mdistRangeNVMT<mtreehelper::t10,MPointer,Mem>,
|
|
mdistRangeNVMT<mtreehelper::t11,MPointer,Mem>,
|
|
mdistRangeNVMT<mtreehelper::t12,MPointer,Mem>,
|
|
|
|
mdistRangeNVMT<mtreehelper::t1,MPointer,MPointer>,
|
|
mdistRangeNVMT<mtreehelper::t2,MPointer,MPointer>,
|
|
mdistRangeNVMT<mtreehelper::t3,MPointer,MPointer>,
|
|
mdistRangeNVMT<mtreehelper::t4,MPointer,MPointer>,
|
|
mdistRangeNVMT<mtreehelper::t5,MPointer,MPointer>,
|
|
mdistRangeNVMT<mtreehelper::t6,MPointer,MPointer>,
|
|
mdistRangeNVMT<mtreehelper::t7,MPointer,MPointer>,
|
|
mdistRangeNVMT<mtreehelper::t8,MPointer,MPointer>,
|
|
mdistRangeNVMT<mtreehelper::t9,MPointer,MPointer>,
|
|
mdistRangeNVMT<mtreehelper::t10,MPointer,MPointer>,
|
|
mdistRangeNVMT<mtreehelper::t11,MPointer,MPointer>,
|
|
mdistRangeNVMT<mtreehelper::t12,MPointer,MPointer>
|
|
};
|
|
|
|
OperatorSpec mdistRangeNSpec(
|
|
"NTREE x MREL x T (x U) x real -> stream(tuple) , NTREE, "
|
|
"MREL represented as string, mem, or mpointer",
|
|
"mem_ntree mem_rel mdistRange[keyAttr, maxDist] ",
|
|
"Retrieves those tuples from a memory relation "
|
|
"having a distance smaller or equals to a given dist "
|
|
"to a key value (or pair of key values). This operation is aided by a memory "
|
|
"based n-tree.",
|
|
"query mkinos_ntree mKinos mdistRange[ alexanderplatz , 2000.0] count"
|
|
);
|
|
|
|
Operator mdistRangeNOp(
|
|
"mdistRangeN",
|
|
mdistRangeNSpec.getStr(),
|
|
48,
|
|
mdistRangeNVM,
|
|
mdistRangeNSelect,
|
|
mdistRangeNTM
|
|
);
|
|
|
|
/*
|
|
Operator ~mdistScan~
|
|
|
|
*/
|
|
ListExpr mdistScanTM(ListExpr args) {
|
|
string err="MTREE(T) x MREL x T (x U) expected";
|
|
if (!nl->HasLength(args, 3) && !nl->HasLength(args, 4)) {
|
|
return listutils::typeError(err + " (wrong number of args)");
|
|
}
|
|
ListExpr a1 = nl->First(args);
|
|
ListExpr a2 = nl->Second(args);
|
|
if (MPointer::checkType(a1)) {
|
|
a1 = nl->Second(a1);
|
|
}
|
|
if (!Mem::checkType(a1)) {
|
|
return listutils::typeError("first arg is not a memory object");
|
|
}
|
|
if (MPointer::checkType(a2)) {
|
|
a2 = nl->Second(a2);
|
|
}
|
|
if (!Mem::checkType(a2)) {
|
|
return listutils::typeError("2nd arg is not a memory object");
|
|
}
|
|
a1 = nl->Second(a1);
|
|
a2 = nl->Second(a2);
|
|
if (!Relation::checkType(a2)) {
|
|
return listutils::typeError("second arg is not a relation");
|
|
}
|
|
ListExpr a3 = nl->Third(args);
|
|
if (nl->HasLength(args, 3)) {
|
|
if (!mtreehelper::checkType(a1, a3)) {
|
|
return listutils::typeError("first arg is not an mtree over "
|
|
+ nl->ToString(a3));
|
|
}
|
|
}
|
|
else {
|
|
ListExpr a4 = nl->Fourth(args);
|
|
if (!mtreehelper::checkType(a1, nl->SymbolAtom(Tuple::BasicType()))) {
|
|
return listutils::typeError("first arg is not an mtree over tuples");
|
|
}
|
|
if (!temporalalgebra::MPoint::checkType(a3) &&
|
|
!temporalalgebra::CUPoint::checkType(a3) &&
|
|
!temporalalgebra::CMPoint::checkType(a3)) {
|
|
return listutils::typeError("third arg is not a (m|cu|cm)point");
|
|
}
|
|
if (!stj::isSymbolicType(a4)) {
|
|
return listutils::typeError("fourth arg is not an mlabel(s) / mplace(s)");
|
|
}
|
|
}
|
|
return nl->TwoElemList(listutils::basicSymbol<Stream<Tuple> >(),
|
|
nl->Second(a2));
|
|
}
|
|
|
|
template<class T, class DistComp>
|
|
class distScanInfo {
|
|
public:
|
|
distScanInfo(MemoryMtreeObject<T, DistComp>* mtree, MemoryRelObject* mrel,
|
|
T* ref) {
|
|
rel = mrel->getmmrel();
|
|
MTreeEntry<T> p(*ref, 0);
|
|
// pair<T,TupleId> p(*ref,0);
|
|
it = mtree->getmtree()->nnSearch(p);
|
|
}
|
|
|
|
~distScanInfo() {
|
|
delete it;
|
|
}
|
|
|
|
Tuple* next() {
|
|
while(true) {
|
|
const MTreeEntry<T>* p = it->next();
|
|
// const pair<T,TupleId>* p = it->next();
|
|
if (!p) {
|
|
return 0;
|
|
}
|
|
if ((p->getTid() <= rel->size()) && (p->getTid() > 0)) {
|
|
Tuple* res = (*rel)[p->getTid() - 1];
|
|
if (res) { // ignore deleted tuples
|
|
res->IncReference();
|
|
return res;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int getNoDistFunCalls() {
|
|
return it->getNoDistFunCalls();
|
|
}
|
|
|
|
|
|
private:
|
|
vector<Tuple*>* rel;
|
|
NNIterator<MTreeEntry<T>, DistComp>* it;
|
|
// NNIterator<pair<T,TupleId> , StdDistComp<T>,
|
|
// MemCloner<pair<T,TupleId> > >* it;
|
|
};
|
|
|
|
template<class K, class T, class R>
|
|
int mdistScanVMT(Word* args, Word& result, int message, Word& local,
|
|
Supplier s) {
|
|
distScanInfo<K, StdDistComp<K> >* li =
|
|
(distScanInfo<K, StdDistComp<K> >*) local.addr;
|
|
switch(message) {
|
|
case OPEN : {
|
|
if(li){
|
|
delete li;
|
|
local.addr = 0;
|
|
}
|
|
R* relN = (R*) args[1].addr;
|
|
MemoryRelObject* mro;
|
|
if (R::requiresTypeCheckInVM()) {
|
|
mro = getMemRel(relN, nl->Second(qp->GetType(s)));
|
|
} else {
|
|
mro = getMemRel(relN);
|
|
}
|
|
if (!mro) {
|
|
return 0;
|
|
}
|
|
K* key = (K*)args[2].addr;
|
|
T* tree = (T*)args[0].addr;
|
|
MemoryMtreeObject<K, StdDistComp<K> >* m = getMtree<T, K>(tree);
|
|
if (m) {
|
|
local.addr = new distScanInfo<K, StdDistComp<K> >(m, mro, key);
|
|
}
|
|
return 0;
|
|
}
|
|
case REQUEST : {
|
|
result.addr = li ? li->next() : 0;
|
|
return result.addr ? YIELD : CANCEL;
|
|
}
|
|
case CLOSE : {
|
|
if (li) {
|
|
mtreehelper::increaseCounter("counterMDistScan",
|
|
li->getNoDistFunCalls());
|
|
delete li;
|
|
local.addr = 0;
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
template<class K, class L, class T, class R>
|
|
int mdistScanVMT2(Word* args, Word& result, int message, Word& local,
|
|
Supplier s) {
|
|
distScanInfo<pair<K, L>, StdDistCompExt<K ,L> >* li =
|
|
(distScanInfo<pair<K, L>, StdDistCompExt<K, L> >*) local.addr;
|
|
switch (message) {
|
|
case OPEN : {
|
|
if (li) {
|
|
delete li;
|
|
local.addr = 0;
|
|
}
|
|
R* relN = (R*) args[1].addr;
|
|
MemoryRelObject* mro;
|
|
if (R::requiresTypeCheckInVM()) {
|
|
mro = getMemRel(relN, nl->Second(qp->GetType(s)));
|
|
} else {
|
|
mro = getMemRel(relN);
|
|
}
|
|
if (!mro) {
|
|
return 0;
|
|
}
|
|
K* key1 = (K*)args[2].addr;
|
|
L* key2 = (L*)args[3].addr;
|
|
T* tree = (T*)args[0].addr;
|
|
pair<K, L> key(*key1, *key2);
|
|
MemoryMtreeObject<pair<K, L>, StdDistCompExt<K, L> >* m =
|
|
getMtree<T, K, L>(tree);
|
|
if (m) {
|
|
local.addr = new distScanInfo<pair<K, L>, StdDistCompExt<K, L> >(m, mro,
|
|
&key);
|
|
}
|
|
return 0;
|
|
}
|
|
case REQUEST : {
|
|
result.addr = li ? li->next() : 0;
|
|
return result.addr ? YIELD : CANCEL;
|
|
}
|
|
case CLOSE : {
|
|
if (li) {
|
|
mtreehelper::increaseCounter("counterMDistScan",
|
|
li->getNoDistFunCalls());
|
|
delete li;
|
|
local.addr = 0;
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
// note: if adding attributes with flobs, the value mapping must be changed
|
|
|
|
ValueMapping mdistScanVM[] = {
|
|
mdistScanVMT<mtreehelper::t1, Mem, Mem>,
|
|
mdistScanVMT<mtreehelper::t2, Mem, Mem>,
|
|
mdistScanVMT<mtreehelper::t3, Mem, Mem>,
|
|
mdistScanVMT<mtreehelper::t4, Mem, Mem>,
|
|
mdistScanVMT<mtreehelper::t5, Mem, Mem>,
|
|
mdistScanVMT<mtreehelper::t6, Mem, Mem>,
|
|
mdistScanVMT<mtreehelper::t7, Mem, Mem>,
|
|
mdistScanVMT<mtreehelper::t8, Mem, Mem>,
|
|
mdistScanVMT<mtreehelper::t9, Mem, Mem>,
|
|
mdistScanVMT<mtreehelper::t10, Mem, Mem>,
|
|
mdistScanVMT<mtreehelper::t11, Mem, Mem>,
|
|
mdistScanVMT<mtreehelper::t12, Mem, Mem>,
|
|
|
|
mdistScanVMT<mtreehelper::t1, Mem, MPointer>,
|
|
mdistScanVMT<mtreehelper::t2, Mem, MPointer>,
|
|
mdistScanVMT<mtreehelper::t3, Mem, MPointer>,
|
|
mdistScanVMT<mtreehelper::t4, Mem, MPointer>,
|
|
mdistScanVMT<mtreehelper::t5, Mem, MPointer>,
|
|
mdistScanVMT<mtreehelper::t6, Mem, MPointer>,
|
|
mdistScanVMT<mtreehelper::t7, Mem, MPointer>,
|
|
mdistScanVMT<mtreehelper::t8, Mem, MPointer>,
|
|
mdistScanVMT<mtreehelper::t9, Mem, MPointer>,
|
|
mdistScanVMT<mtreehelper::t10, Mem, MPointer>,
|
|
mdistScanVMT<mtreehelper::t11, Mem, MPointer>,
|
|
mdistScanVMT<mtreehelper::t12, Mem, MPointer>,
|
|
|
|
mdistScanVMT<mtreehelper::t1, MPointer, Mem>,
|
|
mdistScanVMT<mtreehelper::t2, MPointer, Mem>,
|
|
mdistScanVMT<mtreehelper::t3, MPointer, Mem>,
|
|
mdistScanVMT<mtreehelper::t4, MPointer, Mem>,
|
|
mdistScanVMT<mtreehelper::t5, MPointer, Mem>,
|
|
mdistScanVMT<mtreehelper::t6, MPointer, Mem>,
|
|
mdistScanVMT<mtreehelper::t7, MPointer, Mem>,
|
|
mdistScanVMT<mtreehelper::t8, MPointer, Mem>,
|
|
mdistScanVMT<mtreehelper::t9, MPointer, Mem>,
|
|
mdistScanVMT<mtreehelper::t10, MPointer, Mem>,
|
|
mdistScanVMT<mtreehelper::t11, MPointer, Mem>,
|
|
mdistScanVMT<mtreehelper::t12, MPointer, Mem>,
|
|
|
|
mdistScanVMT<mtreehelper::t1, MPointer, MPointer>,
|
|
mdistScanVMT<mtreehelper::t2, MPointer, MPointer>,
|
|
mdistScanVMT<mtreehelper::t3, MPointer, MPointer>,
|
|
mdistScanVMT<mtreehelper::t4, MPointer, MPointer>,
|
|
mdistScanVMT<mtreehelper::t5, MPointer, MPointer>,
|
|
mdistScanVMT<mtreehelper::t6, MPointer, MPointer>,
|
|
mdistScanVMT<mtreehelper::t7, MPointer, MPointer>,
|
|
mdistScanVMT<mtreehelper::t8, MPointer, MPointer>,
|
|
mdistScanVMT<mtreehelper::t9, MPointer, MPointer>,
|
|
mdistScanVMT<mtreehelper::t10, MPointer, MPointer>,
|
|
mdistScanVMT<mtreehelper::t11, MPointer, MPointer>,
|
|
mdistScanVMT<mtreehelper::t12, MPointer, MPointer>,
|
|
|
|
mdistScanVMT2<temporalalgebra::MPoint, stj::MLabel, Mem, Mem>,
|
|
mdistScanVMT2<temporalalgebra::CUPoint, stj::MLabel, Mem, Mem>,
|
|
mdistScanVMT2<temporalalgebra::CMPoint, stj::MLabel, Mem, Mem>,
|
|
mdistScanVMT2<temporalalgebra::MPoint, stj::MLabels, Mem, Mem>,
|
|
mdistScanVMT2<temporalalgebra::CUPoint, stj::MLabels, Mem, Mem>,
|
|
mdistScanVMT2<temporalalgebra::CMPoint, stj::MLabels, Mem, Mem>,
|
|
mdistScanVMT2<temporalalgebra::MPoint, stj::MPlace, Mem, Mem>,
|
|
mdistScanVMT2<temporalalgebra::CUPoint, stj::MPlace, Mem, Mem>,
|
|
mdistScanVMT2<temporalalgebra::CMPoint, stj::MPlace, Mem, Mem>,
|
|
mdistScanVMT2<temporalalgebra::MPoint, stj::MPlaces, Mem, Mem>,
|
|
mdistScanVMT2<temporalalgebra::CUPoint, stj::MPlaces, Mem, Mem>,
|
|
mdistScanVMT2<temporalalgebra::CMPoint, stj::MPlaces, Mem, Mem>,
|
|
|
|
mdistScanVMT2<temporalalgebra::MPoint, stj::MLabel, Mem, MPointer>,
|
|
mdistScanVMT2<temporalalgebra::CUPoint, stj::MLabel, Mem, MPointer>,
|
|
mdistScanVMT2<temporalalgebra::CMPoint, stj::MLabel, Mem, MPointer>,
|
|
mdistScanVMT2<temporalalgebra::MPoint, stj::MLabels, Mem, MPointer>,
|
|
mdistScanVMT2<temporalalgebra::CUPoint, stj::MLabels, Mem, MPointer>,
|
|
mdistScanVMT2<temporalalgebra::CMPoint, stj::MLabels, Mem, MPointer>,
|
|
mdistScanVMT2<temporalalgebra::MPoint, stj::MPlace, Mem, MPointer>,
|
|
mdistScanVMT2<temporalalgebra::CUPoint, stj::MPlace, Mem, MPointer>,
|
|
mdistScanVMT2<temporalalgebra::CMPoint, stj::MPlace, Mem, MPointer>,
|
|
mdistScanVMT2<temporalalgebra::MPoint, stj::MPlaces, Mem, MPointer>,
|
|
mdistScanVMT2<temporalalgebra::CUPoint, stj::MPlaces, Mem, MPointer>,
|
|
mdistScanVMT2<temporalalgebra::CMPoint, stj::MPlaces, Mem, MPointer>,
|
|
|
|
mdistScanVMT2<temporalalgebra::MPoint, stj::MLabel, MPointer, Mem>,
|
|
mdistScanVMT2<temporalalgebra::CUPoint, stj::MLabel, MPointer, Mem>,
|
|
mdistScanVMT2<temporalalgebra::CMPoint, stj::MLabel, MPointer, Mem>,
|
|
mdistScanVMT2<temporalalgebra::MPoint, stj::MLabels, MPointer, Mem>,
|
|
mdistScanVMT2<temporalalgebra::CUPoint, stj::MLabels, MPointer, Mem>,
|
|
mdistScanVMT2<temporalalgebra::CMPoint, stj::MLabels, MPointer, Mem>,
|
|
mdistScanVMT2<temporalalgebra::MPoint, stj::MPlace, MPointer, Mem>,
|
|
mdistScanVMT2<temporalalgebra::CUPoint, stj::MPlace, MPointer, Mem>,
|
|
mdistScanVMT2<temporalalgebra::CMPoint, stj::MPlace, MPointer, Mem>,
|
|
mdistScanVMT2<temporalalgebra::MPoint, stj::MPlaces, MPointer, Mem>,
|
|
mdistScanVMT2<temporalalgebra::CUPoint, stj::MPlaces, MPointer, Mem>,
|
|
mdistScanVMT2<temporalalgebra::CMPoint, stj::MPlaces, MPointer, Mem>,
|
|
|
|
mdistScanVMT2<temporalalgebra::MPoint, stj::MLabel, MPointer, MPointer>,
|
|
mdistScanVMT2<temporalalgebra::CUPoint, stj::MLabel, MPointer, MPointer>,
|
|
mdistScanVMT2<temporalalgebra::CMPoint, stj::MLabel, MPointer, MPointer>,
|
|
mdistScanVMT2<temporalalgebra::MPoint, stj::MLabels, MPointer, MPointer>,
|
|
mdistScanVMT2<temporalalgebra::CUPoint, stj::MLabels, MPointer, MPointer>,
|
|
mdistScanVMT2<temporalalgebra::CMPoint, stj::MLabels, MPointer, MPointer>,
|
|
mdistScanVMT2<temporalalgebra::MPoint, stj::MPlace, MPointer, MPointer>,
|
|
mdistScanVMT2<temporalalgebra::CUPoint, stj::MPlace, MPointer, MPointer>,
|
|
mdistScanVMT2<temporalalgebra::CMPoint, stj::MPlace, MPointer, MPointer>,
|
|
mdistScanVMT2<temporalalgebra::MPoint, stj::MPlaces, MPointer, MPointer>,
|
|
mdistScanVMT2<temporalalgebra::CUPoint, stj::MPlaces, MPointer, MPointer>,
|
|
mdistScanVMT2<temporalalgebra::CMPoint, stj::MPlaces, MPointer, MPointer>
|
|
};
|
|
|
|
OperatorSpec mdistScanSpec(
|
|
"MTREE x MREL x T (x U) -> stream(tuple) , "
|
|
"MTREE, MREL represented as string, mem, or mpointer",
|
|
"mem_mtree mem_rel mdistScan[keyAttr] ",
|
|
"Retrieves tuples from an memory relation in increasing "
|
|
"distance to a reference object (or pair of reference objects) aided by a "
|
|
"memory based m-tree.",
|
|
"query mkinos_mtree mKinos mdistScan[ alexanderplatz] consume"
|
|
);
|
|
|
|
Operator mdistScanOp(
|
|
"mdistScan",
|
|
mdistScanSpec.getStr(),
|
|
96,
|
|
mdistScanVM,
|
|
mdistRangeScanSelect<3>,
|
|
mdistScanTM
|
|
);
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// NEW
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
Operators of MainMemory2Algebra
|
|
|
|
7.1 Operator ~mwrap~
|
|
|
|
Converts a string into an mem(X) according to the
|
|
stored type in the memory catalog
|
|
|
|
7.1.1 Type Mapping Functions of operator ~mwrap~
|
|
string -> mem(X)
|
|
|
|
*/
|
|
ListExpr mwrapTM(ListExpr args){
|
|
if(!nl->HasLength(args,1)){
|
|
return listutils::typeError("one argument expected");
|
|
}
|
|
ListExpr first = nl->First(args);
|
|
if(!nl->HasLength(first,2)) {
|
|
return listutils::typeError("internal error");
|
|
}
|
|
ListExpr type = nl->First(first);
|
|
ListExpr value = nl->Second(first);
|
|
if(!CcString::checkType(type)){
|
|
return listutils::typeError("string expected");
|
|
}
|
|
ListExpr res;
|
|
string error;
|
|
if(!getMemTypeFromString(type, value,res, error, true)){
|
|
return listutils::typeError(error);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
/*
|
|
|
|
7.1.2 Value Mapping Function of operator ~mwrap~
|
|
|
|
*/
|
|
template<int strpos>
|
|
int mwrapVM(Word* args, Word& result,
|
|
int message, Word& local, Supplier s) {
|
|
CcString* arg = (CcString*) args[strpos].addr;
|
|
result = qp->ResultStorage(s);
|
|
Mem* res = (Mem*) result.addr;
|
|
bool def = arg->IsDefined();
|
|
string v = def?arg->GetValue():"";
|
|
res->set(def,v);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
|
|
7.1.3 Description of operator ~mwrap~
|
|
|
|
*/
|
|
OperatorSpec mwrapSpec(
|
|
"string -> mem(X)",
|
|
"mwrap(_)",
|
|
"Converts a string into a mem object"
|
|
" according to the type from the memory catalog",
|
|
"query mwrap(\"ten\")"
|
|
);
|
|
|
|
/*
|
|
|
|
7.1.4 Instance of operator ~mwrap~
|
|
|
|
*/
|
|
Operator mwrapOp(
|
|
"mwrap",
|
|
mwrapSpec.getStr(),
|
|
mwrapVM<0>,
|
|
Operator::SimpleSelect,
|
|
mwrapTM
|
|
);
|
|
|
|
|
|
/*
|
|
Operator ~mwrap2~
|
|
|
|
This operator may create an mem(x) object without accessing the
|
|
memory catalog to get the type. Instead of this, the type is
|
|
given explicitely in the first argument. The type must be a
|
|
constant text but the string may be any expression that evaluates
|
|
to string. The value mapping checks the equqlity between the
|
|
given type and the actual type. If not, the mem object will be
|
|
undefined.
|
|
|
|
*/
|
|
ListExpr mwrap2TM(ListExpr args){
|
|
if(!nl->HasLength(args,2)){
|
|
return listutils::typeError("2 args expected");
|
|
}
|
|
if(!checkUsesArgs(args)){
|
|
return listutils::typeError("internal error");
|
|
}
|
|
if(!FText::checkType(nl->First(nl->First(args)))){
|
|
return listutils::typeError("first arg is not a text");
|
|
}
|
|
if(!CcString::checkType(nl->First(nl->Second(args)))){
|
|
return listutils::typeError("second arg is not a string");
|
|
}
|
|
ListExpr typeList = nl->Second(nl->First(args));
|
|
if(nl->AtomType(typeList)!=TextType){
|
|
return listutils::typeError("the text is not constant");
|
|
}
|
|
string type = nl->Text2String(typeList);
|
|
if(!nl->ReadFromString(type,typeList)){
|
|
return listutils::typeError("the type is not a valid nested list");
|
|
}
|
|
ListExpr res = nl->TwoElemList(
|
|
listutils::basicSymbol<Mem>(),
|
|
typeList
|
|
);
|
|
if(!Mem::checkType(res)){
|
|
return listutils::typeError("type is not a valid mem type");
|
|
}
|
|
return res;
|
|
}
|
|
|
|
OperatorSpec mwrap2Spec(
|
|
"text x string -> mem(X)",
|
|
"mwrap2(_,_)",
|
|
"Creates a mem object whose type is given "
|
|
"as a text in nested list format",
|
|
"query mwrap2('string', \"myName\")"
|
|
);
|
|
|
|
Operator mwrap2Op(
|
|
"mwrap2",
|
|
mwrap2Spec.getStr(),
|
|
mwrapVM<1>,
|
|
Operator::SimpleSelect,
|
|
mwrap2TM
|
|
);
|
|
|
|
|
|
/*
|
|
Another variant determining the subtype from an expression.
|
|
|
|
*/
|
|
ListExpr mwrap3TM(ListExpr args){
|
|
if(!nl->HasLength(args,2)){
|
|
return listutils::typeError("two args expected");
|
|
}
|
|
if(!CcString::checkType(nl->Second(args))){
|
|
return listutils::typeError("second arg is not a string");
|
|
}
|
|
ListExpr res = nl->TwoElemList(
|
|
listutils::basicSymbol<Mem>(),
|
|
nl->First(args));
|
|
if(!Mem::checkType(res)){
|
|
return listutils::typeError("first arg is not a valid mem subtype");
|
|
}
|
|
return res;
|
|
}
|
|
|
|
|
|
OperatorSpec mwrap3Spec(
|
|
"X x string -> mem(X)",
|
|
"mwrap3(_,_)",
|
|
"Creates a mem object whose type is given "
|
|
"by the first argument. The value of the first "
|
|
"argument is not used",
|
|
"query mwrap2('string', \"myName\")"
|
|
);
|
|
|
|
Operator mwrap3Op(
|
|
"mwrap3",
|
|
mwrap3Spec.getStr(),
|
|
mwrapVM<1>,
|
|
Operator::SimpleSelect,
|
|
mwrap3TM
|
|
);
|
|
|
|
|
|
|
|
|
|
template<int pos>
|
|
ListExpr MTUPLETM(ListExpr args){
|
|
|
|
if(!nl->HasMinLength(args,pos)){
|
|
return listutils::typeError("too less arguments, expected "
|
|
+ stringutils::int2str(pos) + " but got "
|
|
+ stringutils::int2str(nl->ListLength(args)));
|
|
}
|
|
// remove elements before pos
|
|
for(int i=1; i<pos;i++){
|
|
args = nl->Rest(args);
|
|
}
|
|
ListExpr subtype;
|
|
if(!getMemSubType(nl->First(args), subtype)) {
|
|
return listutils::typeError("the specified argument ist not "
|
|
"a memory object");
|
|
}
|
|
ListExpr res;
|
|
if(nl->HasMinLength(subtype,2)){
|
|
res = nl->Second(subtype); // enclosed tuple: stream, rel, orel ...
|
|
} else {
|
|
return listutils::typeError("unsupported subtype");
|
|
}
|
|
if(!Tuple::checkType(res)){
|
|
return listutils::typeError("no tuple found");
|
|
}
|
|
return res;
|
|
}
|
|
|
|
OperatorSpec MTUPLESpec(
|
|
"... MREL x ... -> X or string -> tuple, MREL in {tring,mem,mpointer} ",
|
|
"MTUPLE<X>(_)",
|
|
"Retrieves the tuple type of a memory relation at position "
|
|
"<X> in the argument list",
|
|
"query mten mupdatebyid[[const tid value 5]; No: .No + 10000] count"
|
|
);
|
|
|
|
Operator MTUPLEOp(
|
|
"MTUPLE",
|
|
MTUPLESpec.getStr(),
|
|
0,
|
|
Operator::SimpleSelect,
|
|
MTUPLETM<1>
|
|
);
|
|
|
|
Operator MTUPLE2Op(
|
|
"MTUPLE2",
|
|
MTUPLESpec.getStr(),
|
|
0,
|
|
Operator::SimpleSelect,
|
|
MTUPLETM<2>
|
|
);
|
|
|
|
|
|
|
|
|
|
/*
|
|
7.2 Operator ~mcreatettree~
|
|
|
|
The operator creates a TTree over a given main memory relation.
|
|
|
|
7.2.1 Type Mapping Functions of operator ~mcreatettree~
|
|
{mpointer , mem(rel(...))} x IDENT -> mpointer(mem(ttree X))
|
|
|
|
the first parameter identifies the main memory relation,
|
|
the second parameter identifies the attribute
|
|
|
|
*/
|
|
ListExpr mcreatettreeTypeMap(ListExpr args){
|
|
|
|
if(!nl->HasLength(args,2)){
|
|
return listutils::typeError("two arguments expected");
|
|
}
|
|
|
|
ListExpr second = nl->Second(args);
|
|
if(nl->AtomType(second)!=SymbolType){
|
|
return listutils::typeError("second argument is not a valid "
|
|
"attribute name");
|
|
}
|
|
ListExpr first = nl->First(args);
|
|
if(MPointer::checkType(first)){
|
|
first = nl->Second(first); // just remove the mpointer
|
|
}
|
|
if(!Mem::checkType(first)){
|
|
return listutils::typeError("first argument not of type mpointer "
|
|
"or mem");
|
|
}
|
|
ListExpr rel = nl->Second(first); // remove mem
|
|
if(!Relation::checkType(rel)){
|
|
return listutils::typeError("first argument is not a memory relation");
|
|
}
|
|
ListExpr attrList = nl->Second(nl->Second(rel));
|
|
string aname = nl->SymbolValue(second);
|
|
ListExpr attrType;
|
|
int index = listutils::findAttribute(attrList, aname, attrType);
|
|
if(!index){
|
|
return listutils::typeError("attribute " + aname
|
|
+ " not part of the relation");
|
|
}
|
|
ListExpr resType = MPointer::wrapType(Mem::wrapType(
|
|
MemoryTTreeObject::wrapType(attrType)));
|
|
return nl->ThreeElemList( nl->SymbolAtom(Symbols::APPEND()),
|
|
nl->OneElemList( nl->IntAtom(index-1)),
|
|
resType);
|
|
|
|
}
|
|
|
|
MemoryTTreeObject* createMTTreeOver(MemoryRelObject* mmrel,int attrPos,
|
|
ListExpr resType) {
|
|
|
|
vector<Tuple*>* relation = mmrel->getmmrel();
|
|
vector<Tuple*>::iterator it = relation->begin();
|
|
unsigned int i = 1;
|
|
|
|
memttree* tree = new memttree(8,10);
|
|
size_t usedMainMemory = 0;
|
|
unsigned long availableMemSize = catalog->getAvailableMemSize();
|
|
while(it != relation->end()) {
|
|
Tuple* tup = *it;
|
|
if(tup){
|
|
Attribute* attr = tup->GetAttribute(attrPos);
|
|
AttrIdPair tPair(attr, i);
|
|
|
|
// size for a pair is 16 bytes, plus an additional pointer 8 bytes
|
|
size_t entrySize = 24;
|
|
if (entrySize<availableMemSize){
|
|
tree->insert(tPair);
|
|
usedMainMemory += (entrySize);
|
|
availableMemSize -= (entrySize);
|
|
} else {
|
|
cout << "there is not enough main memory available"
|
|
" to create an TTree" << endl;
|
|
delete tree;
|
|
return 0;
|
|
}
|
|
}
|
|
i++;
|
|
it++;
|
|
}
|
|
MemoryTTreeObject* ttreeObject =
|
|
new MemoryTTreeObject(tree,
|
|
usedMainMemory,
|
|
nl->ToString(resType),
|
|
mmrel->hasflob(),
|
|
getDBname());
|
|
return ttreeObject;
|
|
}
|
|
/*
|
|
|
|
7.2.3 Value Mapping Functions of operator ~mcreatettree~
|
|
|
|
*/
|
|
int mcreatettreeVMMem(
|
|
Word* args, Word& result,
|
|
int message, Word& local, Supplier s) {
|
|
|
|
result = qp->ResultStorage(s);
|
|
MPointer* res = static_cast<MPointer*>(result.addr);
|
|
|
|
// the main memory relation
|
|
Mem* rel = (Mem*) args[0].addr;
|
|
if(!rel->IsDefined()){
|
|
res->setPointer(0);
|
|
return 0;
|
|
}
|
|
string name = rel->GetValue();
|
|
int attrPos = ((CcInt*) args[2].addr)->GetValue();
|
|
|
|
ListExpr type = catalog->getMMObjectTypeExpr(name);
|
|
|
|
ListExpr memType = qp->GetType(qp->GetSon(s,0));
|
|
if(!nl->Equal(type,memType)){
|
|
cerr << "Types of memory representation and type in catalog differ";
|
|
cerr << "Type in TM was " << nl->ToString(memType) << endl;
|
|
cerr << "Type in catalkog is " << nl->ToString(type) << endl;
|
|
res->setPointer(0);
|
|
return 0;
|
|
}
|
|
|
|
// get main memory relation
|
|
MemoryRelObject* mmrel =
|
|
(MemoryRelObject*)catalog->getMMObject(name);
|
|
if(!mmrel){
|
|
res->setPointer(0);
|
|
return 0;
|
|
}
|
|
|
|
MemoryTTreeObject* mmtree = createMTTreeOver(mmrel, attrPos,
|
|
nl->Second(qp->GetType(s)));
|
|
res->setPointer(mmtree);
|
|
mmtree->deleteIfAllowed();
|
|
return 0;
|
|
}
|
|
|
|
|
|
int mcreatettreeVMMP(
|
|
Word* args, Word& result,
|
|
int message, Word& local, Supplier s) {
|
|
result = qp->ResultStorage(s);
|
|
MPointer* res = static_cast<MPointer*>(result.addr);
|
|
int attrPos = ((CcInt*) args[2].addr)->GetValue();
|
|
MPointer* rel = (MPointer*) args[0].addr;
|
|
MemoryRelObject* mmrel = (MemoryRelObject*) rel->GetValue();
|
|
if(!mmrel){
|
|
res->setPointer(0);
|
|
return 0;
|
|
}
|
|
MemoryTTreeObject* mmtree = createMTTreeOver(mmrel, attrPos,
|
|
nl->Second(qp->GetType(s)));
|
|
res->setPointer(mmtree);
|
|
mmtree->deleteIfAllowed();
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
|
|
7.2.4 Value Mapping Array and Selection
|
|
|
|
*/
|
|
ValueMapping mcreatettreeVM[] =
|
|
{
|
|
mcreatettreeVMMP,
|
|
mcreatettreeVMMem
|
|
};
|
|
|
|
int mcreatettreeSelect(ListExpr args){
|
|
return MPointer::checkType(nl->First(args))?0:1;
|
|
}
|
|
|
|
/*
|
|
|
|
7.2.5 Description of operator ~mcreatettree~
|
|
|
|
*/
|
|
OperatorSpec mcreatettreeSpec(
|
|
"MREL x IDENT -> mpointer(mem(ttree X)) ",
|
|
"_ mcreatettree [_]",
|
|
"Creates an T-Tree over a main memory relation given by the"
|
|
"first argument and an attribute given by the second argument",
|
|
"query mStaedte mcreatettree [SName]"
|
|
);
|
|
|
|
/*
|
|
|
|
7.1.6 Instance of operator ~mcreatettree~
|
|
|
|
*/
|
|
|
|
Operator mcreatettreeOp (
|
|
"mcreatettree",
|
|
mcreatettreeSpec.getStr(),
|
|
2,
|
|
mcreatettreeVM,
|
|
mcreatettreeSelect,
|
|
mcreatettreeTypeMap
|
|
);
|
|
|
|
|
|
/*
|
|
|
|
7.3 Operator ~minsertttree~, ~mdeletettree~
|
|
|
|
These operators insert, delete or update objects in a main memory ttree index.
|
|
They receive a stream of tuples (including an attribute tid), whose attributes,
|
|
determined by the third argument, will be either inserted, deleted or updated
|
|
in the tree.
|
|
|
|
7.3.1 Type Mapping Functions of operator ~minsertttree~,
|
|
~mdeletettree~.
|
|
|
|
*/
|
|
enum ChangeTypeTree {
|
|
MInsertTree,
|
|
MDeleteTree
|
|
};
|
|
|
|
template<class TreeType>
|
|
ListExpr minsertdeletetreeTypeMap(ListExpr args){
|
|
|
|
if(nl->ListLength(args)!=3) {
|
|
return listutils::typeError("three arguments expected");
|
|
}
|
|
|
|
ListExpr stream = nl->First(args); //stream + query
|
|
|
|
if(!listutils::isTupleStream(stream)){
|
|
return listutils::typeError("first argument must be a tuple stream");
|
|
}
|
|
|
|
// check if last attribute is of type 'tid'
|
|
ListExpr rest = nl->Second(nl->Second(stream));
|
|
ListExpr next;
|
|
while (!(nl->IsEmpty(rest))) {
|
|
next = nl->First(rest);
|
|
rest = nl->Rest(rest);
|
|
}
|
|
if(!TupleIdentifier::checkType(nl->Second(next))) {
|
|
return listutils::typeError("last attribute in the tuple must be a tid");
|
|
}
|
|
|
|
// allow ttree or avl ttree as second argument
|
|
ListExpr second = nl->Second(args);
|
|
ListExpr tree;
|
|
if(!getMemSubType(second,tree)){
|
|
return listutils::typeError("second arg is not a memory object");
|
|
}
|
|
if(!TreeType::checkType(tree)) {
|
|
return listutils::typeError("second arg is not a memory tree");
|
|
}
|
|
|
|
// check attribute
|
|
ListExpr third = nl->Third(args);
|
|
if(nl->AtomType(third)!=SymbolType) {
|
|
return listutils::typeError("third argument is not a valid "
|
|
"attribute name");
|
|
}
|
|
|
|
string attrName = nl->SymbolValue(third);
|
|
ListExpr attrType = 0;
|
|
int attrPos = 0;
|
|
ListExpr attrList = nl->Second(nl->Second(stream));
|
|
attrPos = listutils::findAttribute(attrList, attrName, attrType);
|
|
|
|
if (attrPos == 0){
|
|
return listutils::typeError
|
|
("there is no attribute having name " + attrName);
|
|
}
|
|
|
|
|
|
ListExpr append = nl->OneElemList(nl->IntAtom(attrPos));
|
|
|
|
return nl->ThreeElemList(
|
|
nl->SymbolAtom(Symbol::APPEND()),
|
|
append,
|
|
stream);
|
|
}
|
|
|
|
|
|
template<ChangeTypeTree ct, class TreeType, class TreeElem>
|
|
class minsertdeleteInfo {
|
|
public:
|
|
|
|
typedef TreeType treetype;
|
|
|
|
minsertdeleteInfo(Word& w, TreeType* _tree, int _attrPos)
|
|
: stream(w), tree(_tree), attrPos(_attrPos) {
|
|
stream.open();
|
|
}
|
|
|
|
~minsertdeleteInfo(){
|
|
stream.close();
|
|
}
|
|
|
|
|
|
Tuple* next(){
|
|
Tuple* res = stream.request();
|
|
if(!res) {
|
|
return 0;
|
|
}
|
|
|
|
Attribute* tidAttr = res->GetAttribute(res->GetNoAttributes() - 1);
|
|
TupleId oldTid = ((TupleIdentifier*)tidAttr)->GetTid();
|
|
Attribute* attr = res->GetAttribute(attrPos-1);
|
|
TreeElem elem = TreeElem(attr,oldTid);
|
|
switch(ct){
|
|
case MInsertTree : tree->insert(elem); break;
|
|
case MDeleteTree : tree->remove(elem); break;
|
|
default: assert(false);
|
|
}
|
|
return res;
|
|
}
|
|
private:
|
|
Stream<Tuple> stream;
|
|
TreeType* tree;
|
|
int attrPos;
|
|
};
|
|
|
|
|
|
/*
|
|
|
|
7.3.2 The Value Mapping Functions of operator ~minsertttree~
|
|
and ~mdeletettree~
|
|
|
|
*/
|
|
template<class T, class LocalInfo, class MemTree>
|
|
int minserttreeValueMap (Word* args, Word& result,
|
|
int message, Word& local, Supplier s) {
|
|
|
|
LocalInfo* li = (LocalInfo*) local.addr;
|
|
|
|
|
|
switch(message) {
|
|
|
|
|
|
case OPEN : {
|
|
if(li) {
|
|
delete li;
|
|
local.addr = 0;
|
|
}
|
|
|
|
T* tree = (T*) args[1].addr;
|
|
if(!tree->IsDefined()){
|
|
// cout << "undefined" << endl;
|
|
return 0;
|
|
}
|
|
string name = tree->GetValue();
|
|
// cut blank from the front
|
|
stringutils::trim(name);
|
|
|
|
|
|
|
|
MemTree* mmtree =(MemTree*) catalog->getMMObject(name);
|
|
if(!mmtree) {
|
|
return 0;
|
|
}
|
|
|
|
int attrPos = ((CcInt*) args[3].addr)->GetValue();
|
|
|
|
|
|
cout << "*********************************" << endl;
|
|
cout << "AttrPos = " << attrPos << endl;
|
|
cout << "*********************************" << endl;
|
|
|
|
|
|
local.addr = new LocalInfo(args[0],
|
|
mmtree->gettree(),
|
|
attrPos);
|
|
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 0;
|
|
|
|
}
|
|
|
|
template<class LocalInfo, class MemTree>
|
|
int minserttreeMPointerValueMap (Word* args, Word& result,
|
|
int message, Word& local, Supplier s) {
|
|
|
|
LocalInfo* li = (LocalInfo*) local.addr;
|
|
|
|
switch(message) {
|
|
|
|
case OPEN : {
|
|
if(li) {
|
|
delete li;
|
|
local.addr = 0;
|
|
}
|
|
|
|
MPointer* tree = (MPointer*) args[1].addr;
|
|
MemTree* mmtree =(MemTree*) (*tree)();
|
|
if(!mmtree) {
|
|
return 0;
|
|
}
|
|
int attrPos = ((CcInt*) args[3].addr)->GetValue();
|
|
local.addr = new LocalInfo(args[0],
|
|
mmtree->gettree(),
|
|
attrPos);
|
|
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 0;
|
|
|
|
}
|
|
|
|
/*
|
|
7.3.3 Value Mapping Array and Selection
|
|
|
|
*/
|
|
ValueMapping minsertttreeVM[] = {
|
|
|
|
// insert
|
|
minserttreeValueMap<Mem,minsertdeleteInfo<MInsertTree,
|
|
memttree, AttrIdPair>, MemoryTTreeObject >,
|
|
minserttreeMPointerValueMap<minsertdeleteInfo<MInsertTree,
|
|
memttree, AttrIdPair>, MemoryTTreeObject >,
|
|
|
|
// delete
|
|
minserttreeValueMap<Mem,minsertdeleteInfo<MDeleteTree,
|
|
memttree, AttrIdPair>, MemoryTTreeObject >,
|
|
minserttreeMPointerValueMap<minsertdeleteInfo<MDeleteTree,
|
|
memttree, AttrIdPair>, MemoryTTreeObject >
|
|
};
|
|
|
|
template<ChangeTypeTree ct>
|
|
int minsertttreeSelect(ListExpr args){
|
|
ListExpr a1 = nl->Second(args);
|
|
int n1 = -1;
|
|
if(Mem::checkType(a1)) n1 = 0;
|
|
if(MPointer::checkType(a1)) n1 = 1;
|
|
if(n1<0) return -1;
|
|
|
|
if(ct==MInsertTree)
|
|
return n1;
|
|
else if(ct==MDeleteTree)
|
|
return n1+2;
|
|
}
|
|
|
|
/*
|
|
7.3.4 Description of operator ~minsertttree~
|
|
|
|
*/
|
|
|
|
OperatorSpec minsertttreeSpec(
|
|
"stream(tuple(x@[TID:tid])) x MTTREE x IDENT "
|
|
"-> stream(tuple(x@[TID:tid])) , MTTREE in {string, mem, mpointer}",
|
|
"_ op [_,_]",
|
|
"inserts an object into a main memory ttree",
|
|
"query ten feed head[5] minsert[mten] "
|
|
"minsertttree[mten_No, No] count"
|
|
);
|
|
|
|
/*
|
|
7.3.5 Instance of operator ~minsertttree~
|
|
|
|
*/
|
|
Operator minsertttreeOp (
|
|
"minsertttree",
|
|
minsertttreeSpec.getStr(),
|
|
4,
|
|
minsertttreeVM,
|
|
minsertttreeSelect<MInsertTree>,
|
|
minsertdeletetreeTypeMap<MemoryTTreeObject>
|
|
);
|
|
|
|
/*
|
|
7.4.4 Description of operator ~mdeletettree~
|
|
|
|
*/
|
|
|
|
OperatorSpec mdeletettreeSpec(
|
|
"stream(tuple(x@[TID:tid])) x MTTREExIDENT "
|
|
"-> stream(tuple(x@[TID:tid])) , MTTREE in {mem, mpointer}",
|
|
"_ op [_,_]",
|
|
"deletes an object identified by tupleid from a main memory ttree",
|
|
"query ten feed head[5] mdelete[mten] "
|
|
"mdeletettree[mten_No, No] count"
|
|
);
|
|
|
|
/*
|
|
7.4.5 Instance of operator ~mdeletettree~
|
|
|
|
*/
|
|
Operator mdeletettreeOp (
|
|
"mdeletettree",
|
|
mdeletettreeSpec.getStr(),
|
|
4,
|
|
minsertttreeVM,
|
|
minsertttreeSelect<MDeleteTree>,
|
|
minsertdeletetreeTypeMap<MemoryTTreeObject>
|
|
);
|
|
|
|
/*
|
|
7.5 ~insert~ and ~delete~ for AVL trees
|
|
|
|
*/
|
|
|
|
OperatorSpec minsertavltreeSpec(
|
|
"stream(tuple(x@[TID:tid])) x AVLTREE x IDENT "
|
|
"-> stream(tuple(x@[TID:tid])), AVLTREE iun {string, mem, mpointer}",
|
|
"_ op [_,_]",
|
|
"inserts an object into a main memory avltree",
|
|
"query ten feed head[5] minsert[mten] "
|
|
"minsertavltree[mten_No, No] count"
|
|
);
|
|
|
|
|
|
ValueMapping minsertAVLtreeVM[] = {
|
|
minserttreeValueMap<Mem,minsertdeleteInfo<MInsertTree,
|
|
memAVLtree, AttrIdPair>, MemoryAVLObject >,
|
|
minserttreeMPointerValueMap<minsertdeleteInfo<MInsertTree,
|
|
memAVLtree, AttrIdPair>, MemoryAVLObject >,
|
|
};
|
|
|
|
int minsertavltreeSelect(ListExpr args){
|
|
ListExpr a1 = nl->Second(args);
|
|
if(Mem::checkType(a1)) return 0;
|
|
if(MPointer::checkType(a1)) return 1;
|
|
return -1;
|
|
}
|
|
|
|
|
|
Operator minsertavltreeOp (
|
|
"minsertavltree",
|
|
minsertavltreeSpec.getStr(),
|
|
2,
|
|
minsertAVLtreeVM,
|
|
minsertavltreeSelect,
|
|
minsertdeletetreeTypeMap<MemoryAVLObject>
|
|
);
|
|
|
|
|
|
OperatorSpec mdeleteavltreeSpec(
|
|
"stream(tuple(x@[TID:tid])) x AVLTREE x ident "
|
|
"-> stream(tuple(x@[TID:tid])), AVLTREE in {mem, mpointer}",
|
|
"_ op [_,_]",
|
|
"Removes objects from a main memory avltree",
|
|
"query ten feed head[5] modelete[mten] "
|
|
"mdeleteavltree[mten_No, No] count"
|
|
);
|
|
|
|
|
|
ValueMapping mdeleteAVLtreeVM[] = {
|
|
minserttreeValueMap<Mem,minsertdeleteInfo<MDeleteTree,
|
|
memAVLtree, AttrIdPair>, MemoryAVLObject >,
|
|
minserttreeMPointerValueMap<minsertdeleteInfo<MDeleteTree,
|
|
memAVLtree, AttrIdPair>, MemoryAVLObject >
|
|
};
|
|
|
|
int mdeleteavltreeSelect(ListExpr args){
|
|
ListExpr a1 = nl->Second(args);
|
|
if(Mem::checkType(a1)) return 0;
|
|
if(MPointer::checkType(a1)) return 1;
|
|
return -1;
|
|
}
|
|
|
|
|
|
Operator mdeleteavltreeOp (
|
|
"mdeleteavltree",
|
|
mdeleteavltreeSpec.getStr(),
|
|
2,
|
|
mdeleteAVLtreeVM,
|
|
mdeleteavltreeSelect,
|
|
minsertdeletetreeTypeMap<MemoryAVLObject>
|
|
);
|
|
|
|
|
|
/*
|
|
7.6 Operators ~mcreateinsertrel~, ~mcreatedeleterel~ and
|
|
~mcreateupdaterel~
|
|
|
|
These operators create an auxiliary relation with the same tuple schema
|
|
as the given relation including an attribute tid. In case of
|
|
~mcreateupdaterel~, additionally all attributes with an appended sting
|
|
'old' are added to the schema.
|
|
|
|
7.6.1 General Type mapping function of operators ~mcreateinsertrel~,
|
|
~mcreatedeleterel~ and ~mcreateupdaterel~
|
|
|
|
*/
|
|
ListExpr mcreateAuxiliaryRelTM(const ListExpr& args,
|
|
const string opName) {
|
|
|
|
if(nl->HasLength(args,2) && !nl->HasLength(args,1)) {
|
|
return listutils::typeError("one argument expected");
|
|
}
|
|
if(nl->HasLength(args,2)){
|
|
if(!CcBool::checkType(nl->Second(args))){
|
|
return listutils::typeError("second arg is not of type bool");
|
|
}
|
|
}
|
|
|
|
ListExpr first = nl->First(args);
|
|
if(!MPointer::checkType(first)){
|
|
return listutils::typeError("mpointer(mem(P)) expected");
|
|
}
|
|
// remove mpointer and mem from type
|
|
first = nl->Second(nl->Second(first));
|
|
|
|
// check for rel
|
|
bool isOrel;
|
|
if(Relation::checkType(first)) {
|
|
isOrel = false;
|
|
} else if(listutils::isOrelDescription(first)) {
|
|
isOrel = true;
|
|
} else {
|
|
return listutils::typeError(
|
|
"first arg is not a memory relation or ordered relation");
|
|
}
|
|
|
|
// build first part of the result-tupletype
|
|
ListExpr rest = nl->Second(nl->Second(first));
|
|
ListExpr listn = nl->OneElemList(nl->First(rest));
|
|
ListExpr lastlistn = listn;
|
|
rest = nl->Rest(rest);
|
|
while(!(nl->IsEmpty(rest))) {
|
|
lastlistn = nl->Append(lastlistn,nl->First(rest));
|
|
rest = nl->Rest(rest);
|
|
}
|
|
|
|
if(opName == "mcreateupdaterel") {
|
|
// Append once again all attributes from the argument-relation
|
|
// to the result-tupletype but the names of the attributes
|
|
// extendend by 'old'
|
|
|
|
rest = nl->Second(nl->Second(first));
|
|
string oldName;
|
|
ListExpr oldAttribute;
|
|
while (!(nl->IsEmpty(rest))) {
|
|
nl->WriteToString(oldName, nl->First(nl->First(rest)));
|
|
oldName += "_old";
|
|
oldAttribute =
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom(oldName),
|
|
nl->Second(nl->First(rest)));
|
|
lastlistn = nl->Append(lastlistn,oldAttribute);
|
|
rest = nl->Rest(rest);
|
|
}
|
|
}
|
|
|
|
//Append last attribute for the tupleidentifier
|
|
lastlistn = nl->Append(lastlistn,
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom("TID"),
|
|
nl->SymbolAtom(TupleIdentifier::BasicType())));
|
|
|
|
ListExpr outlist;
|
|
|
|
|
|
if(!isOrel) {
|
|
outlist = nl->TwoElemList(
|
|
listutils::basicSymbol<Mem>(),
|
|
nl->TwoElemList(
|
|
listutils::basicSymbol<Relation>(),
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom(Tuple::BasicType()),
|
|
listn)));
|
|
} else {
|
|
outlist = nl->TwoElemList(
|
|
listutils::basicSymbol<Mem>(),
|
|
nl->ThreeElemList(
|
|
nl->SymbolAtom(OREL),
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom(Tuple::BasicType()),
|
|
listn),
|
|
nl->Third(first)));
|
|
}
|
|
ListExpr resType = MPointer::wrapType(outlist);
|
|
if(nl->HasLength(args,1)){
|
|
return nl->ThreeElemList( nl->SymbolAtom(Symbols::APPEND()),
|
|
nl->OneElemList(nl->BoolAtom(false)),
|
|
resType);
|
|
|
|
} else {
|
|
return resType;
|
|
}
|
|
}
|
|
|
|
ListExpr mcreateinsertrelTM(ListExpr args) {
|
|
return mcreateAuxiliaryRelTM(args, "mcreateinsertrel");
|
|
}
|
|
|
|
ListExpr mcreatedeleterelTM(ListExpr args) {
|
|
return mcreateAuxiliaryRelTM(args, "mcreatedeleterel");
|
|
}
|
|
|
|
ListExpr mcreateupdaterelTM(ListExpr args) {
|
|
return mcreateAuxiliaryRelTM(args, "mcreateupdaterel");
|
|
}
|
|
|
|
/*
|
|
7.6.2 General Value mapping function of operators ~mcreateinsertrel~,
|
|
~mcreatedeleterel~ and ~mcreateupdaterel~
|
|
|
|
*/
|
|
template<bool isORel>
|
|
int mcreateauxiliaryrelVMT(Word* args, Word& result, int message,
|
|
Word& local, Supplier s) {
|
|
result = qp->ResultStorage(s);
|
|
MPointer* mp = (MPointer*) result.addr;
|
|
ListExpr resType = qp->GetType(s);
|
|
MPointer* arg = (MPointer*) args[0].addr;
|
|
if(arg->isNull()) return 0;
|
|
|
|
resType = nl->Second(resType); // remove mpointer
|
|
CcBool* Flob = (CcBool*) args[1].addr;
|
|
bool flob = Flob->IsDefined() && Flob->GetValue();
|
|
if(!isORel){
|
|
vector<Tuple*>* v = new vector<Tuple*>();
|
|
MemoryRelObject* mrel = new MemoryRelObject(v,0,nl->ToString(resType),
|
|
flob, getDBname());
|
|
mp->setPointer(mrel);
|
|
mrel->deleteIfAllowed();
|
|
} else {
|
|
ttree::TTree<TupleWrap,TupleComp>* t;
|
|
t = new ttree::TTree<TupleWrap,TupleComp>(16,18);
|
|
MemoryORelObject* moa = (MemoryORelObject*) arg->GetValue();
|
|
vector<int>* va = moa->getAttrPos();
|
|
vector<int>* vr = new vector<int>();
|
|
for(size_t i=0;i<vr->size();i++){
|
|
vr->push_back(va->at(i));
|
|
}
|
|
MemoryORelObject* mor = new MemoryORelObject(t,vr,0,
|
|
nl->ToString(resType),flob,
|
|
getDBname());
|
|
mp->setPointer(mor);
|
|
mor->deleteIfAllowed();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
ValueMapping mcreateauxiliaryrelVM[] = {
|
|
mcreateauxiliaryrelVMT<false>,
|
|
mcreateauxiliaryrelVMT<true>
|
|
};
|
|
|
|
int mcreateauxiliaryrelSelect(ListExpr args){
|
|
ListExpr rel = nl->Second(nl->Second(nl->First(args)));
|
|
return Relation::checkType(rel)?0:1;
|
|
}
|
|
|
|
/*
|
|
7.6.4 Specification of operator ~mcreateinsertrel~
|
|
|
|
*/
|
|
OperatorSpec mcreateinsertrelSpec(
|
|
"mpointer(mem(rel)) [x bool] -> mpointer(mem(rel(tuple(x@[TID:tid]))))",
|
|
"mcreateinsertrel(_)",
|
|
"creates an auxiliary relation",
|
|
"query mcreateinsertrel(mten))"
|
|
);
|
|
|
|
|
|
/*
|
|
7.6.5 Definition of operator ~mcreateinsertrel~
|
|
|
|
*/
|
|
Operator mcreateinsertrelOp (
|
|
"mcreateinsertrel", // name
|
|
mcreateinsertrelSpec.getStr(), // specification
|
|
2,
|
|
mcreateauxiliaryrelVM, // value mapping
|
|
mcreateauxiliaryrelSelect, // trivial selection function
|
|
mcreateinsertrelTM // type mapping
|
|
);
|
|
|
|
|
|
/*
|
|
7.7.4 Specification of operator ~mcreatedeleterel~
|
|
|
|
*/
|
|
OperatorSpec mcreatedeleterelSpec(
|
|
"MREL -> mem(rel(tuple(x@[TID:tid]))) ",
|
|
"mcreatedeleterel(_) , MREL in {string, mem, mpointer}",
|
|
"creates an auxiliary relation",
|
|
"let fuenf = mcreatedeleterel(mten)"
|
|
);
|
|
|
|
/*
|
|
7.7.5 Definition of operator ~mcreatedeleterel~
|
|
|
|
*/
|
|
Operator mcreatedeleterelOp(
|
|
"mcreatedeleterel", // name
|
|
mcreatedeleterelSpec.getStr(), // specification
|
|
2,
|
|
mcreateauxiliaryrelVM, // value mapping
|
|
mcreateauxiliaryrelSelect, // trivial selection function
|
|
mcreatedeleterelTM // type mapping
|
|
);
|
|
|
|
|
|
/*
|
|
7.8.4 Specification of operator ~mcreateupdaterel~
|
|
|
|
*/
|
|
|
|
OperatorSpec mcreateupdaterelSpec(
|
|
" MREL(tuple(X)) -> mem(rel(tuple(x@[(a1_old x1)..."
|
|
"(an_old xn)(TID:tid)]))), MREL in {string, mem, mpointer}",
|
|
"mcreateupdaterel(_)",
|
|
"creates an auxiliary relation",
|
|
"let fuenf = mcreateupdaterel(mten))"
|
|
);
|
|
|
|
|
|
/*
|
|
7.8.5 Definition of operator ~mcreateupdaterel~
|
|
|
|
*/
|
|
Operator mcreateupdaterelOp (
|
|
"mcreateupdaterel", // name
|
|
mcreateupdaterelSpec.getStr(), // specification
|
|
2,
|
|
mcreateauxiliaryrelVM, // value mapping
|
|
mcreateauxiliaryrelSelect, // selection function
|
|
mcreateupdaterelTM // type mapping
|
|
);
|
|
|
|
|
|
|
|
|
|
/*
|
|
7.9 Operator ~minsert~
|
|
|
|
Inserts each tuple of the inputstream into the memory relation. Returns
|
|
a stream of tuples which is basically the same as the inputstream
|
|
but each tuple extended by an attribute of type 'tid' which is the
|
|
tupleidentifier of the inserted tuple in the extended relation.
|
|
|
|
7.9.1 General type mapping function of operators ~minsert~, ~minsertsave~,
|
|
~mdelete~ and ~mdeletesave~
|
|
|
|
stream(tuple(x)) x {string, mem(rel(...))} -> stream(tuple(x@[TID:tid])) or
|
|
|
|
stream(tuple(x)) x {string, mem(rel(...))} x {string, mem(rel(...))}
|
|
-> stream(tuple(x@[TID:tid]))
|
|
|
|
|
|
|
|
*/
|
|
template<int noargs, bool ordered>
|
|
ListExpr minsertTypeMap(ListExpr args) {
|
|
|
|
if(!nl->HasLength(args,noargs)) {
|
|
return listutils::typeError("wrong number of arguments");
|
|
}
|
|
|
|
ListExpr stream = nl->First(args);
|
|
|
|
// process stream
|
|
if(!Stream<Tuple>::checkType(stream)){
|
|
return listutils::typeError("first argument must be a tuple stream");
|
|
}
|
|
|
|
string errMsg;
|
|
|
|
// process second argument (mem(rel))
|
|
ListExpr second;
|
|
if(!getMemSubType(nl->Second(args), second)){
|
|
return listutils::typeError("second arg is not a memory object");
|
|
}
|
|
|
|
if(ordered){
|
|
if(!listutils::isOrelDescription(second)){
|
|
return listutils::typeError(
|
|
"second arg is not an ordered memory relation");
|
|
}
|
|
} else {
|
|
if((!Relation::checkType(second))){
|
|
return listutils::typeError(
|
|
"second arg is not a memory relation");
|
|
}
|
|
}
|
|
|
|
if(!nl->Equal(nl->Second(stream), nl->Second(second))){
|
|
return listutils::typeError("stream type and mem relation type differ\n"
|
|
"stream: " + nl->ToString(stream) + "\n"
|
|
+ "rel : " + nl->ToString(second));
|
|
}
|
|
|
|
// append tupleidentifier
|
|
ListExpr rest = nl->Second(nl->Second(second));
|
|
ListExpr at;
|
|
if(listutils::findAttribute(rest,"TID",at)>0){
|
|
return listutils::typeError("There is already an TID attribute");
|
|
}
|
|
ListExpr listn = nl->OneElemList(nl->First(rest));
|
|
ListExpr lastlistn = listn;
|
|
rest = nl->Rest(rest);
|
|
while (!(nl->IsEmpty(rest))) {
|
|
lastlistn = nl->Append(lastlistn,nl->First(rest));
|
|
rest = nl->Rest(rest);
|
|
}
|
|
|
|
|
|
lastlistn = nl->Append(lastlistn,
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom("TID"),
|
|
nl->SymbolAtom(TupleIdentifier::BasicType())));
|
|
|
|
// process third argument (minsertsave only)
|
|
if(nl->ListLength(args)==3) {
|
|
ListExpr third;
|
|
if(!getMemSubType(nl->Third(args),third)){
|
|
return listutils::typeError("second arg is not a Memory object");
|
|
}
|
|
if(!Relation::checkType(third)){
|
|
return listutils::typeError(
|
|
"third arg is not a memory relation");
|
|
}
|
|
// the scheme of this relation must be equal to the output tuple scheme
|
|
if(!nl->Equal(listn, nl->Second(nl->Second(third)))){
|
|
return listutils::typeError("Scheme of the auxiliary relation is not "
|
|
"equal to the main relation + TID");
|
|
}
|
|
}
|
|
return nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()),
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom(Tuple::BasicType()),
|
|
listn));
|
|
}
|
|
|
|
|
|
class minsertInfo {
|
|
public:
|
|
minsertInfo(Word& w, vector<Tuple*>* _relation,
|
|
bool _flob, TupleType* _type)
|
|
: stream(w),relation(_relation), flob(_flob) {
|
|
type = _type;
|
|
type->IncReference();
|
|
stream.open();
|
|
}
|
|
|
|
~minsertInfo(){
|
|
stream.close();
|
|
type->DeleteIfAllowed();
|
|
}
|
|
|
|
Tuple* next(){
|
|
Tuple* res = stream.request();
|
|
|
|
if(!res) {return 0; }
|
|
|
|
if(flob) {
|
|
res->bringToMemory();
|
|
}
|
|
|
|
Tuple* newtup = new Tuple(type);
|
|
for(int i = 0; i < res->GetNoAttributes(); i++) {
|
|
newtup->CopyAttribute(i,res,i);
|
|
}
|
|
|
|
|
|
// add the main memory tuple id to the output tuple
|
|
Attribute* tidAttr = new TupleIdentifier(true,
|
|
relation->size()+1);
|
|
newtup->PutAttribute(res->GetNoAttributes(), tidAttr);
|
|
relation->push_back(res);
|
|
newtup->SetTupleId(relation->size());
|
|
|
|
return newtup;
|
|
}
|
|
|
|
private:
|
|
Stream<Tuple> stream;
|
|
vector<Tuple*>* relation;
|
|
bool flob;
|
|
TupleType* type;
|
|
};
|
|
|
|
|
|
/*
|
|
|
|
7.9.2 Value Mapping Function of operator ~minsert~
|
|
|
|
*/
|
|
template<class T>
|
|
int minsertValMap (Word* args, Word& result,
|
|
int message, Word& local, Supplier s) {
|
|
|
|
typedef pair<MemoryRelObject*,TupleType*> globalInfo;
|
|
minsertInfo* li = (minsertInfo*) local.addr;
|
|
globalInfo* gi = (globalInfo*) qp->GetLocal2(s).addr;
|
|
|
|
switch (message) {
|
|
|
|
case INIT: {
|
|
TupleType* tt = new TupleType(nl->Second(GetTupleResultType(s)));
|
|
gi = new globalInfo(0,tt);
|
|
qp->GetLocal2(s).addr=gi;
|
|
return 0;
|
|
}
|
|
|
|
case FINISH: {
|
|
if(gi){
|
|
gi->first=0;
|
|
gi->second->DeleteIfAllowed();
|
|
delete gi;
|
|
qp->GetLocal2(s).addr = 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
case OPEN : {
|
|
if(li) {
|
|
delete li;
|
|
local.addr=0;
|
|
}
|
|
|
|
|
|
assert(gi);
|
|
|
|
if(!gi->first){
|
|
T* oN = (T*) args[1].addr;
|
|
MemoryRelObject* rel = getMemRel(oN);
|
|
if(!rel) return 0;
|
|
gi->first = rel;
|
|
}
|
|
MemoryRelObject* mmr=gi->first;
|
|
TupleType* tt = gi->second;
|
|
|
|
local.addr = new minsertInfo(args[0],mmr->getmmrel(),mmr->hasflob(),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 0;
|
|
|
|
}
|
|
|
|
ValueMapping minsertVM[] = {
|
|
minsertValMap<Mem>,
|
|
minsertValMap<MPointer>,
|
|
|
|
};
|
|
|
|
int minsertSelect(ListExpr args){
|
|
ListExpr t = nl->Second(args);
|
|
if(Mem::checkType(t)) return 0;
|
|
if(MPointer::checkType(t)) return 1;
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
7.9.4 Description of operator ~minsert~
|
|
|
|
*/
|
|
|
|
OperatorSpec minsertSpec(
|
|
"stream(tuple(x)) x MREAL -> stream(tuple(x@[TID:tid])), "
|
|
"MREL in {string, mem, mpointer}",
|
|
"_ minsert [_]",
|
|
"inserts the tuples of a stream into an "
|
|
"existing main memory relation. All tuples get an additional "
|
|
"attribute of type 'tid'",
|
|
"query minsert (ten feed head[5],mten) count"
|
|
);
|
|
|
|
/*
|
|
7.9.5 Instance of operator ~minsert~
|
|
|
|
*/
|
|
Operator minsertOp (
|
|
"minsert",
|
|
minsertSpec.getStr(),
|
|
2,
|
|
minsertVM,
|
|
minsertSelect,
|
|
minsertTypeMap<2,false>
|
|
);
|
|
|
|
|
|
/*
|
|
7.10 Operator ~minsertsave~
|
|
|
|
Inserts each tuple of the inputstream into the memory relation. Returns
|
|
a stream of tuples which is basically the same as the inputstream
|
|
but each tuple extended by an attribute of type 'tid' which is the
|
|
tupleidentifier of the inserted tuple in the extended relation.
|
|
Additionally the tuple of the input stream are saved in an auxiliary
|
|
main memory realtion.
|
|
|
|
*/
|
|
class minsertsaveInfo {
|
|
public:
|
|
minsertsaveInfo(Word& w, vector<Tuple*>* _relation,
|
|
vector<Tuple*>* _auxrel,
|
|
bool _flob, ListExpr _type)
|
|
: stream(w),relation(_relation), auxrel(_auxrel),
|
|
flob(_flob) {
|
|
stream.open();
|
|
type = new TupleType(_type);
|
|
}
|
|
|
|
~minsertsaveInfo(){
|
|
stream.close();
|
|
type->DeleteIfAllowed();
|
|
}
|
|
|
|
Tuple* next(){
|
|
Tuple* res = stream.request();
|
|
if(!res){
|
|
return 0;
|
|
}
|
|
|
|
if(flob){
|
|
res->bringToMemory();
|
|
}
|
|
|
|
//get tuple id and append it to tuple
|
|
Tuple* newtup = new Tuple(type);
|
|
for(int i = 0; i < res->GetNoAttributes(); i++){
|
|
newtup->CopyAttribute(i,res,i);
|
|
}
|
|
Attribute* tidAttr = new TupleIdentifier(true,relation->size()+1);
|
|
newtup->PutAttribute(res->GetNoAttributes(), tidAttr);
|
|
|
|
// insert tuple in memory relation
|
|
relation->push_back(res);
|
|
// insert tuple in auxrel
|
|
auxrel->push_back(newtup);
|
|
newtup->IncReference();
|
|
|
|
return newtup;
|
|
}
|
|
|
|
private:
|
|
Stream<Tuple> stream;
|
|
vector<Tuple*>* relation;
|
|
vector<Tuple*>* auxrel;
|
|
bool flob;
|
|
TupleType* type;
|
|
};
|
|
|
|
|
|
/*
|
|
7.10.2 Value Mapping Functions of operator ~minsertsave~
|
|
|
|
*/
|
|
template<class R,class A>
|
|
int minsertsaveValueMap (Word* args, Word& result,
|
|
int message, Word& local, Supplier s) {
|
|
|
|
minsertsaveInfo* li = (minsertsaveInfo*) local.addr;
|
|
|
|
switch (message) {
|
|
|
|
case OPEN : {
|
|
|
|
if(li) {
|
|
delete li;
|
|
local.addr=0;
|
|
}
|
|
|
|
qp->Open(args[0].addr);
|
|
|
|
R* oN = (R*) args[1].addr;
|
|
A* aux = (A*) args[2].addr;
|
|
|
|
MemoryRelObject* rel = getMemRel(oN);;
|
|
if(!rel) { return 0; }
|
|
MemoryRelObject* auxrel = getMemRel(aux);;
|
|
if(!auxrel) { return 0; }
|
|
|
|
ListExpr tt = nl->Second(GetTupleResultType(s));
|
|
|
|
local.addr = new minsertsaveInfo(args[0],rel->getmmrel(),
|
|
auxrel->getmmrel(),
|
|
rel->hasflob(),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 0;
|
|
|
|
}
|
|
|
|
ValueMapping minsertsaveVM[] = {
|
|
minsertsaveValueMap<Mem,Mem>,
|
|
minsertsaveValueMap<Mem,MPointer>,
|
|
minsertsaveValueMap<MPointer,Mem>,
|
|
minsertsaveValueMap<MPointer,MPointer>
|
|
};
|
|
|
|
int minsertsaveSelect(ListExpr args){
|
|
ListExpr t = nl->Second(args);
|
|
ListExpr a = nl->Third(args);
|
|
|
|
int nt = -1;
|
|
if(Mem::checkType(t)) nt = 0;
|
|
if(MPointer::checkType(t)) nt = 2;
|
|
if(nt<0) return -1;
|
|
|
|
int na = -1;
|
|
if(Mem::checkType(a)) na = 0;
|
|
if(MPointer::checkType(a)) na = 1;
|
|
if(na<0) return -1;
|
|
|
|
return nt + na;
|
|
|
|
|
|
}
|
|
|
|
/*
|
|
7.10.4 Description of operator ~minsertsave~
|
|
|
|
*/
|
|
OperatorSpec minsertsaveSpec(
|
|
"stream(tuple(x)) x MREL1 x MREL2, MREL1,MREL2 in {string, mem, mpointer} "
|
|
"-> stream(tuple(x@[TID:tid]))",
|
|
"_ minsertsave [_,_]",
|
|
"insert all tuple of an input stream into two main memory relations",
|
|
"query ten feed head[5] minsertsave['ten','fuenf'] count"
|
|
);
|
|
|
|
/*
|
|
7.10.5 Instance of operator ~minsertsave~
|
|
|
|
*/
|
|
Operator minsertsaveOp (
|
|
"minsertsave",
|
|
minsertsaveSpec.getStr(),
|
|
4,
|
|
minsertsaveVM,
|
|
minsertsaveSelect,
|
|
minsertTypeMap<3,false>
|
|
);
|
|
|
|
|
|
/*
|
|
7.11 Operator ~minserttuple~
|
|
|
|
This Operator inserts the given list of attributes as a new tuple into
|
|
a main memory relation.
|
|
|
|
7.11.1 General type mapping function of operators ~minserttuple~
|
|
and ~minserttuplesave~.
|
|
|
|
*/
|
|
template<int noArgs>
|
|
ListExpr minserttupleTypeMap(ListExpr args) {
|
|
|
|
|
|
if((nl->ListLength(args)!=noArgs)) {
|
|
return listutils::typeError(stringutils::int2str(noArgs)
|
|
+ " arguments expected");
|
|
}
|
|
// process first argument (mem(rel))
|
|
ListExpr first;
|
|
if(!getMemSubType(nl->First(args),first)){
|
|
return listutils::typeError("first argument is not a memory object");
|
|
}
|
|
if(!Relation::checkType(first)){
|
|
return listutils::typeError("first arg is not a memory relation");
|
|
}
|
|
|
|
// check tuple
|
|
ListExpr second = nl->Second(args);
|
|
if(nl->AtomType(second)!=NoAtom){
|
|
return listutils::typeError("list as second arg expected");
|
|
}
|
|
|
|
if(nl->ListLength(nl->Second(nl->Second(first)))!=nl->ListLength(second)){
|
|
return listutils::typeError("different lengths in tuple and update");
|
|
}
|
|
|
|
// check whether types of relation matches types of attributes
|
|
ListExpr restrel = nl->Second(nl->Second(first));
|
|
ListExpr resttuple = second;
|
|
|
|
while(!(nl->IsEmpty(restrel))) {
|
|
if(!nl->Equal(nl->Second(nl->First(restrel)),nl->First(resttuple))){
|
|
return listutils::typeError("type mismatch in attribute "
|
|
"list and update list");
|
|
}
|
|
restrel = nl->Rest(restrel);
|
|
resttuple = nl->Rest(resttuple);
|
|
}
|
|
|
|
// append tupleid
|
|
restrel = nl->Second(nl->Second(first));
|
|
|
|
ListExpr at;
|
|
if(listutils::findAttribute(restrel,"TID",at)>0){
|
|
return listutils::typeError("TID attribute already present in "
|
|
"argument relation.");
|
|
}
|
|
|
|
ListExpr listn = nl->OneElemList(nl->First(restrel));
|
|
ListExpr lastlistn = listn;
|
|
restrel = nl->Rest(restrel);
|
|
while (!(nl->IsEmpty(restrel))) {
|
|
lastlistn = nl->Append(lastlistn,nl->First(restrel));
|
|
restrel = nl->Rest(restrel);
|
|
}
|
|
|
|
lastlistn = nl->Append(lastlistn,
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom("TID"),
|
|
nl->SymbolAtom(TupleIdentifier::BasicType())));
|
|
|
|
// process third argument (minserttuplesave only)
|
|
if(noArgs==3) {
|
|
ListExpr third;
|
|
if(!getMemSubType(nl->Third(args),third)){
|
|
return listutils::typeError("third arg is not a memory object");
|
|
}
|
|
if(!Relation::checkType(third)){
|
|
return listutils::typeError(
|
|
"third arg is not a memory relation");
|
|
}
|
|
// check whether this relations corresponds to the output tuples
|
|
ListExpr attrList = nl->Second(nl->Second(third));
|
|
if(!nl->Equal(attrList, listn)){
|
|
return listutils::typeError("auxiliary relation type differs to "
|
|
"main relationtype + TID");
|
|
}
|
|
|
|
}
|
|
|
|
|
|
return nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()),
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom(Tuple::BasicType()),
|
|
listn));
|
|
}
|
|
|
|
|
|
class minserttupleInfo{
|
|
public:
|
|
minserttupleInfo(vector<Tuple*>* _relation, bool _flob,
|
|
ListExpr _listType, TupleType* _type, Word& _tupleList)
|
|
: relation(_relation), flob(_flob),
|
|
listType(_listType) ,type(_type), tupleList(_tupleList) {
|
|
|
|
firstcall = true;
|
|
}
|
|
|
|
~minserttupleInfo() {
|
|
type->DeleteIfAllowed();
|
|
}
|
|
|
|
Tuple* next() {
|
|
|
|
if(!firstcall) {
|
|
return 0;
|
|
} else {
|
|
firstcall = false;
|
|
}
|
|
|
|
Tuple* res = new Tuple(type);
|
|
|
|
ListExpr rest = nl->Second(nl->Second(listType));
|
|
ListExpr insertType = nl->OneElemList(nl->First(rest));
|
|
ListExpr last = insertType;
|
|
|
|
rest = nl->Rest(rest);
|
|
while(nl->ListLength(rest)>1) {
|
|
last = nl->Append(last, nl->First(rest));
|
|
rest = nl->Rest(rest);
|
|
}
|
|
insertType = nl->TwoElemList(nl->SymbolAtom(Tuple::BasicType()),
|
|
insertType);
|
|
|
|
TupleType* insertTupleType = new TupleType(insertType);
|
|
Tuple* tup = new Tuple(insertTupleType);
|
|
insertTupleType->DeleteIfAllowed();
|
|
Supplier supplier = tupleList.addr;
|
|
|
|
Supplier s;
|
|
attrValue.addr = 0;
|
|
for(int i=0; i<res->GetNoAttributes()-1; i++) {
|
|
s = qp->GetSupplier(supplier, i);
|
|
qp->Request(s,attrValue);
|
|
Attribute* attr = (Attribute*) attrValue.addr;
|
|
res->PutAttribute(i,attr->Clone());
|
|
tup->CopyAttribute(i,res,i);
|
|
}
|
|
const TupleId& tid = relation->size()+1;
|
|
tup->SetTupleId(tid);
|
|
// add TID
|
|
Attribute* tidAttr = new TupleIdentifier(true,tid);
|
|
res->PutAttribute(res->GetNoAttributes()-1, tidAttr);
|
|
|
|
if(flob){
|
|
tup->bringToMemory();
|
|
}
|
|
// add Tuple to memory relation
|
|
relation->push_back(tup);
|
|
return res;
|
|
}
|
|
|
|
private:
|
|
vector<Tuple*>* relation;
|
|
bool flob;
|
|
ListExpr listType;
|
|
TupleType* type;
|
|
Word tupleList;
|
|
bool firstcall;
|
|
Word attrValue;
|
|
};
|
|
|
|
|
|
/*
|
|
|
|
7.11.2 Value Mapping Function of operator ~minserttuple~
|
|
|
|
*/
|
|
template<class T>
|
|
int minserttupleValMap (Word* args, Word& result,
|
|
int message, Word& local, Supplier s) {
|
|
|
|
minserttupleInfo* li = (minserttupleInfo*) local.addr;
|
|
|
|
switch (message) {
|
|
case OPEN: {
|
|
|
|
if(li) {
|
|
delete li;
|
|
local.addr=0;
|
|
}
|
|
|
|
T* oN = (T*) args[0].addr;
|
|
|
|
MemoryRelObject* rel = getMemRel(oN);
|
|
if(!rel) {
|
|
return 0; }
|
|
|
|
ListExpr tupleType = GetTupleResultType(s);
|
|
TupleType* tt = new TupleType(nl->Second(tupleType));
|
|
|
|
local.addr = new minserttupleInfo(rel->getmmrel(),rel->hasflob(),
|
|
tupleType,tt,args[1]);
|
|
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 0;
|
|
}
|
|
|
|
|
|
ValueMapping minserttupleVM[] = {
|
|
minserttupleValMap<Mem>,
|
|
minserttupleValMap<MPointer>
|
|
};
|
|
|
|
int minserttupleSelect(ListExpr args){
|
|
ListExpr t = nl->First(args);
|
|
if(Mem::checkType(t)) return 0;
|
|
if(MPointer::checkType(t)) return 1;
|
|
return -1;
|
|
}
|
|
|
|
|
|
/*
|
|
7.11.4 Description of operator ~minserttuple~
|
|
|
|
*/
|
|
OperatorSpec minserttupleSpec(
|
|
"MREL x [t1 ... tn] -> stream(tuple(x@[TID:tid])) , "
|
|
"MREL in {string, mem, mpointer}",
|
|
"_ minserttuple [list]",
|
|
"inserts a tuple into a main memory relation",
|
|
"query 'Staedte' minserttuple['AA',34,5666,'899','ZZ'] count"
|
|
);
|
|
|
|
/*
|
|
7.11.5 Instance of operator ~minserttuple~
|
|
|
|
*/
|
|
Operator minserttupleOp (
|
|
"minserttuple",
|
|
minserttupleSpec.getStr(),
|
|
2,
|
|
minserttupleVM,
|
|
minserttupleSelect,
|
|
minserttupleTypeMap<2>
|
|
);
|
|
|
|
|
|
|
|
|
|
/*
|
|
7.12 Operator ~minserttuplesave~
|
|
|
|
The Operator ~minserttuplesave~ adds a tuple to a given main memory relation
|
|
(argument 1) and saves it additionally in an auxiliary main memory
|
|
relation (argument 3).
|
|
|
|
*/
|
|
class minserttuplesaveInfo{
|
|
public:
|
|
minserttuplesaveInfo(vector<Tuple*>* _relation, vector<Tuple*>* _auxrel,
|
|
bool _flob, ListExpr _listType, TupleType* _type,
|
|
Word& _tupleList)
|
|
: relation(_relation), auxrel(_auxrel), flob(_flob),
|
|
listType(_listType) ,type(_type), tupleList(_tupleList) {
|
|
|
|
firstcall = true;
|
|
}
|
|
|
|
~minserttuplesaveInfo() {
|
|
type->DeleteIfAllowed();
|
|
}
|
|
|
|
Tuple* next() {
|
|
|
|
if(!firstcall){
|
|
return 0;
|
|
} else {
|
|
firstcall = false;
|
|
}
|
|
|
|
Tuple* res = new Tuple(type);
|
|
|
|
ListExpr rest = nl->Second(nl->Second(listType));
|
|
ListExpr insertType = nl->OneElemList(nl->First(rest));
|
|
ListExpr last = insertType;
|
|
|
|
rest = nl->Rest(rest);
|
|
while(nl->ListLength(rest)>1) {
|
|
last = nl->Append(last, nl->First(rest));
|
|
rest = nl->Rest(rest);
|
|
}
|
|
insertType = nl->TwoElemList(nl->SymbolAtom(Tuple::BasicType()),
|
|
insertType);
|
|
|
|
|
|
TupleType* insertTupleType = new TupleType(insertType);
|
|
Tuple* tup = new Tuple(insertTupleType);
|
|
insertTupleType->DeleteIfAllowed();
|
|
Supplier supplier = tupleList.addr;
|
|
attrValue.addr = 0;
|
|
Supplier s;
|
|
for(int i=0; i<res->GetNoAttributes()-1; i++) {
|
|
s = qp->GetSupplier(supplier, i);
|
|
qp->Request(s,attrValue);
|
|
Attribute* attr = (Attribute*) attrValue.addr;
|
|
res->PutAttribute(i,attr->Clone());
|
|
tup->CopyAttribute(i,res,i);
|
|
}
|
|
const TupleId tid = relation->size()+1;
|
|
tup->SetTupleId(tid);
|
|
|
|
// add TID
|
|
Attribute* tidAttr = new TupleIdentifier(true,tid);
|
|
res->PutAttribute(res->GetNoAttributes()-1, tidAttr);
|
|
|
|
// flob
|
|
if(flob) {
|
|
tup->bringToMemory();
|
|
}
|
|
|
|
// add Tuple to memory relation
|
|
relation->push_back(tup);
|
|
|
|
// add tuple to auxrel
|
|
res->IncReference();
|
|
auxrel->push_back(res);
|
|
return res;
|
|
}
|
|
|
|
private:
|
|
vector<Tuple*>* relation;
|
|
vector<Tuple*>* auxrel;
|
|
bool flob;
|
|
ListExpr listType;
|
|
TupleType* type;
|
|
Word tupleList;
|
|
bool firstcall;
|
|
Word attrValue;
|
|
};
|
|
|
|
/*
|
|
7.12.2 Value Mapping Function of operator ~minserttuplesave~
|
|
|
|
*/
|
|
template<class R, class A>
|
|
int minserttuplesaveValueMap (Word* args, Word& result,
|
|
int message, Word& local, Supplier s) {
|
|
|
|
minserttuplesaveInfo* li = (minserttuplesaveInfo*) local.addr;
|
|
|
|
switch (message) {
|
|
case OPEN: {
|
|
|
|
if(li) {
|
|
delete li;
|
|
local.addr=0;
|
|
}
|
|
|
|
R* oN = (R*) args[0].addr;
|
|
|
|
ListExpr tupleType = GetTupleResultType(s);
|
|
TupleType* tt = new TupleType(nl->Second(tupleType));
|
|
|
|
A* aux = (A*) args[2].addr;
|
|
|
|
MemoryRelObject* rel = getMemRel(oN);
|
|
if(!rel) { return 0; }
|
|
MemoryRelObject* auxrel = getMemRel(aux);
|
|
if(!auxrel) { return 0; }
|
|
local.addr = new minserttuplesaveInfo(rel->getmmrel(),
|
|
auxrel->getmmrel(),
|
|
rel->hasflob(),
|
|
tupleType,tt,args[1]);
|
|
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 0;
|
|
}
|
|
|
|
|
|
ValueMapping minserttuplesaveVM[] = {
|
|
minserttuplesaveValueMap<Mem,Mem>,
|
|
minserttuplesaveValueMap<Mem,MPointer>,
|
|
minserttuplesaveValueMap<MPointer,Mem>,
|
|
minserttuplesaveValueMap<MPointer,MPointer>,
|
|
};
|
|
|
|
int minserttuplesaveSelect(ListExpr args){
|
|
ListExpr t = nl->First(args);
|
|
ListExpr a = nl->Third(args);
|
|
|
|
int nt = -1;
|
|
if(Mem::checkType(t)) nt = 0;
|
|
if(MPointer::checkType(t)) nt = 2;
|
|
if(nt<0) return -1;
|
|
|
|
int na = -1;
|
|
if(Mem::checkType(a)) na = 0;
|
|
if(MPointer::checkType(a)) na = 1;
|
|
if(na<0) return -1;
|
|
return nt + na;
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
7.12.4 Description of operator ~minserttuplesave~
|
|
|
|
*/
|
|
OperatorSpec minserttuplesaveSpec(
|
|
"MREL1 x [t1 ... tn] x "
|
|
"MREL2 -> stream(tuple(x@[TID:tid])), MREL1, MREL2 "
|
|
"in {string, mem, mpointer}",
|
|
"_ minserttuplesave [list; _]",
|
|
"inserts a tuple into a main memory relation and an auxiliary main "
|
|
"memory relation",
|
|
"query 'Staedte' "
|
|
"minserttuplesave['AusgedachtDorf',34,5666,899,'ZZ'; 'Stadt'] count"
|
|
);
|
|
|
|
/*
|
|
7.12.5 Instance of operator ~minserttuplesave~
|
|
|
|
*/
|
|
Operator minserttuplesaveOp (
|
|
"minserttuplesave",
|
|
minserttupleSpec.getStr(),
|
|
4,
|
|
minserttuplesaveVM,
|
|
minserttuplesaveSelect,
|
|
minserttupleTypeMap<3>
|
|
);
|
|
|
|
|
|
|
|
/*
|
|
7.13 Operator ~mdelete~
|
|
|
|
|
|
7.13.1 Auxiliary function ~remove~
|
|
|
|
This function removes the first tuple in a relation having the
|
|
same attribute values as the given tuple. The tuple id of
|
|
res is set to the former tuple id of the removed tuple.
|
|
If the tuple is not found, its tuple id is set to null.
|
|
|
|
*/
|
|
void remove(vector<Tuple*>* relation, Tuple* res) {
|
|
|
|
for (size_t i = 0; i < relation->size(); i++) {
|
|
Tuple* tup = relation->at(i);
|
|
if(tup){
|
|
bool equal = true;
|
|
for(int j=0; j<tup->GetNoAttributes() && equal; j++) {
|
|
int cmp = ((Attribute*)tup->GetAttribute(j))->Compare(
|
|
((Attribute*)res->GetAttribute(j)));
|
|
if(cmp!=0){
|
|
equal = false;
|
|
}
|
|
}
|
|
if(equal){ // hit
|
|
tup->DeleteIfAllowed();
|
|
(*relation)[i] = 0;
|
|
res->SetTupleId(i+1);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
res->SetTupleId(0);
|
|
}
|
|
|
|
class mdeleteInfo {
|
|
public:
|
|
mdeleteInfo(Word& w,
|
|
vector<Tuple*>* _mainRelation,
|
|
vector<Tuple*>* _auxRelation,
|
|
ListExpr _type)
|
|
: stream(w),
|
|
mainRelation(_mainRelation),
|
|
auxRelation(_auxRelation) {
|
|
type = new TupleType(_type);
|
|
stream.open();
|
|
}
|
|
|
|
~mdeleteInfo(){
|
|
stream.close();
|
|
type->DeleteIfAllowed();
|
|
}
|
|
|
|
Tuple* next() {
|
|
TupleIdentifier* tid;
|
|
while((tid=stream.request())){
|
|
//tid->Print(cout) << endl;
|
|
if(!tid->IsDefined()){
|
|
tid->DeleteIfAllowed();
|
|
} else {
|
|
TupleId id = tid->GetTid();
|
|
if(id<1 || id > mainRelation->size()){
|
|
tid->DeleteIfAllowed();
|
|
} else {
|
|
Tuple* tuple = mainRelation->at(id-1);
|
|
if(!tuple){
|
|
tid->DeleteIfAllowed();
|
|
} else {
|
|
(*mainRelation)[id-1]=0;
|
|
return createResultTuple(tuple,tid);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
private:
|
|
Stream<TupleIdentifier> stream;
|
|
vector<Tuple*>* mainRelation;
|
|
vector<Tuple*>* auxRelation;
|
|
TupleType* type;
|
|
|
|
|
|
Tuple* createResultTuple(Tuple* orig, TupleIdentifier* tid){
|
|
Tuple* res = new Tuple(type);
|
|
assert(res->GetNoAttributes()==orig->GetNoAttributes()+1);
|
|
|
|
|
|
for(int i=0;i<orig->GetNoAttributes(); i++){
|
|
res->CopyAttribute(i,orig,i);
|
|
}
|
|
res->PutAttribute(orig->GetNoAttributes(), tid);
|
|
orig->DeleteIfAllowed();
|
|
res->SetTupleId(tid->GetTid());
|
|
// save tuple if required
|
|
if(auxRelation){
|
|
res->IncReference();
|
|
auxRelation->push_back(res);
|
|
}
|
|
return res;
|
|
}
|
|
};
|
|
|
|
/*
|
|
|
|
7.13 Operator ~mdelete~
|
|
|
|
This Operator deletes all tuples of an input stream from a main memory
|
|
relation. All tuple of the input stream are returned in an output
|
|
stream with an additional Attribut containing the tupleid.
|
|
|
|
7.13.2 Value Mapping Function of operator ~mdelete~
|
|
|
|
*/
|
|
template<bool save>
|
|
ListExpr mdeleteTM(ListExpr args){
|
|
int noargs = save?3:2;
|
|
if(!nl->HasLength(args,noargs)){
|
|
return listutils::typeError("wrong number of arguments");
|
|
}
|
|
if(!Stream<TupleIdentifier>::checkType(nl->First(args))){
|
|
return listutils::typeError("first argument mut be a stream of tids");
|
|
}
|
|
string errMsg;
|
|
ListExpr mainRel;
|
|
if(!getMemSubType(nl->Second(args), mainRel)){
|
|
return listutils::typeError("Second argument is not a memory type");
|
|
}
|
|
|
|
if(!Relation::checkType(mainRel)){
|
|
return listutils::typeError("second arg is not a memory relation");
|
|
}
|
|
ListExpr mat = nl->Second(nl->Second(mainRel));
|
|
// append TID to mtt
|
|
ListExpr at = listutils::concat(mat, nl->OneElemList(
|
|
nl->TwoElemList(nl->SymbolAtom("TID"),
|
|
listutils::basicSymbol<TupleIdentifier>())));
|
|
ListExpr tt = nl->TwoElemList( listutils::basicSymbol<Tuple>(), at);
|
|
ListExpr res = nl->TwoElemList(listutils::basicSymbol<Stream<Tuple> >(),
|
|
tt);
|
|
if(!save){
|
|
return res;
|
|
}
|
|
// check the aux relation
|
|
ListExpr auxRel;
|
|
if(!getMemSubType(nl->Third(args), auxRel)){
|
|
return listutils::typeError("third argument is not a memory object");
|
|
}
|
|
if(!Relation::checkType(auxRel)){
|
|
return listutils::typeError("third arg is not a memory relation");
|
|
}
|
|
if(!nl->Equal(nl->Second(auxRel),tt)){
|
|
return listutils::typeError("auxiliary relation is not main "
|
|
"relation + tid");
|
|
}
|
|
return res;
|
|
}
|
|
|
|
|
|
template<class T, class S, bool save>
|
|
int mdeleteValMap (Word* args, Word& result,
|
|
int message, Word& local, Supplier s) {
|
|
|
|
mdeleteInfo* li = (mdeleteInfo*) local.addr;
|
|
|
|
switch (message) {
|
|
case OPEN : {
|
|
|
|
if(li) {
|
|
delete li;
|
|
local.addr=0;
|
|
}
|
|
|
|
T* oN = (T*) args[1].addr;
|
|
MemoryRelObject* rel = getMemRel(oN);
|
|
if(!rel) {
|
|
return 0;
|
|
}
|
|
|
|
ListExpr tt = nl->Second(GetTupleResultType(s));
|
|
|
|
vector<Tuple*>* aux = 0;
|
|
if(save){
|
|
S* an = (S*) args[2].addr;
|
|
MemoryRelObject* arel = getMemRel(an);
|
|
if(!arel){
|
|
return 0;
|
|
}
|
|
aux = arel->getmmrel();
|
|
}
|
|
|
|
local.addr = new mdeleteInfo(args[0],
|
|
rel->getmmrel(),
|
|
aux,
|
|
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 0;
|
|
}
|
|
|
|
ValueMapping mdeleteVM[] = {
|
|
// the second template argument is ignored in this case
|
|
mdeleteValMap<Mem, Mem, false>,
|
|
mdeleteValMap<MPointer, Mem, false>
|
|
};
|
|
|
|
int mdeleteSelect(ListExpr args){
|
|
ListExpr s = nl->Second(args);
|
|
if(Mem::checkType(s)) return 0;
|
|
if(MPointer::checkType(s)) return 1;
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
7.13.4 Description of operator ~mdelete~
|
|
|
|
*/
|
|
OperatorSpec mdeleteSpec(
|
|
"stream(tid) x MREL -> stream(tuple(x@[TID:tid])), "
|
|
"MREL in {mem, mpointer}",
|
|
"_ mdelete [_]",
|
|
"deletes the tuple of a stream from an "
|
|
"existing main memory relation",
|
|
"query ten feed filter [.No = 2] tids mdelete['ten'] count"
|
|
);
|
|
|
|
/*
|
|
7.13.5 Instance of operator ~mdelete~
|
|
|
|
*/
|
|
Operator mdeleteOp (
|
|
"mdelete",
|
|
mdeleteSpec.getStr(),
|
|
2,
|
|
mdeleteVM,
|
|
mdeleteSelect,
|
|
mdeleteTM<false>
|
|
);
|
|
|
|
|
|
/*
|
|
7.14 Operator ~mdeletesave~
|
|
|
|
The operator ~mdeletesave~ deletes all tuples of an input stream from
|
|
a main memory relation. It returns the stream, all tuples now containing an
|
|
additional attribut of type 'tid' and adds the tuples to an auxiliary
|
|
main memory relation.
|
|
|
|
*/
|
|
|
|
/*
|
|
7.14.2 Value Mapping of operator ~mdeletesave~
|
|
|
|
*/
|
|
ValueMapping mdeletesaveVM[] = {
|
|
mdeleteValMap<Mem, Mem, true>,
|
|
mdeleteValMap<Mem, MPointer,true>,
|
|
mdeleteValMap<MPointer, Mem, true>,
|
|
mdeleteValMap<MPointer, MPointer,true>,
|
|
};
|
|
|
|
int mdeletesaveSelect(ListExpr args){
|
|
ListExpr a2 = nl->Second(args);
|
|
int n1 = -1;
|
|
if(Mem::checkType(a2)) n1 = 0;
|
|
if(MPointer::checkType(a2)) n1 = 2;
|
|
|
|
ListExpr a3 = nl->Third(args);
|
|
int n2 = -1;
|
|
if(Mem::checkType(a3)) n2 = 0;
|
|
if(MPointer::checkType(a3)) n2 = 1;
|
|
|
|
if(n1<0 || n2<0) return -1;
|
|
return n1+n2;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
7.14.4 Description of operator ~mdeletesave~
|
|
|
|
*/
|
|
|
|
OperatorSpec mdeletesaveSpec(
|
|
"stream(tid) x {mem(rel),mpointer} "
|
|
"x {mem(rel),mpointer} -> stream(Tuple)",
|
|
"_ mdeletesave[_,_]",
|
|
"Deletes tuples with given ids from a relation and stores "
|
|
"deleted tuple into a auxiliary relation. ",
|
|
"query mten mfeed filter[.No > 6] tids "
|
|
"mdeletesave[mtenm, mtenDel] count"
|
|
);
|
|
|
|
/*
|
|
7.1.5 Instance of operator ~mdeletesave~
|
|
|
|
*/
|
|
Operator mdeletesaveOp (
|
|
"mdeletesave",
|
|
mdeletesaveSpec.getStr(),
|
|
4,
|
|
mdeletesaveVM,
|
|
mdeletesaveSelect,
|
|
mdeleteTM<true>
|
|
);
|
|
|
|
|
|
|
|
/*
|
|
7.2 Operator ~mdeletebyid~
|
|
|
|
The Operator ~mdeletebyid~ deletes all tuples possessing a given
|
|
TupleIdentifier from a main memory relation. It returns the deleted
|
|
Tuple including a new attribute of type `tid` as a stream.
|
|
|
|
7.15.1 Type Mapping Funktion for operator ~mdeletebyid~
|
|
|
|
{string, mem(rel(tuple(x)))} x (tid) -> stream(tuple(x@[TID:tid]))
|
|
|
|
*/
|
|
ListExpr mdeletebyidTypeMap(ListExpr args) {
|
|
|
|
if(nl->ListLength(args) != 2) {
|
|
return listutils::typeError("wrong number of arguments");
|
|
}
|
|
|
|
ListExpr first;
|
|
if(!getMemSubType(nl->First(args),first)){
|
|
return listutils::typeError("first argument is not a memory object");
|
|
}
|
|
if(!Relation::checkType(first)){
|
|
return listutils::typeError("first arg is not a memory relation");
|
|
}
|
|
|
|
// process second arg (tid)
|
|
ListExpr second = nl->Second(args);
|
|
if(!TupleIdentifier::checkType(second)){
|
|
return listutils::typeError("second argument must be a tid");
|
|
}
|
|
|
|
ListExpr rest = nl->Second(nl->Second(first));
|
|
ListExpr at;
|
|
if(listutils::findAttribute(rest,"TID",at)){
|
|
return listutils::typeError("Relation has a TID attribute");
|
|
}
|
|
ListExpr attrlist = nl->OneElemList(nl->First(rest));
|
|
ListExpr currentattr = attrlist;
|
|
rest = nl->Rest(rest);
|
|
while (!(nl->IsEmpty(rest))) {
|
|
currentattr = nl->Append(currentattr,nl->First(rest));
|
|
rest = nl->Rest(rest);
|
|
}
|
|
|
|
currentattr = nl->Append(currentattr,
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom("TID"),
|
|
nl->SymbolAtom(TupleIdentifier::BasicType())));
|
|
|
|
return nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()),
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom(Tuple::BasicType()),
|
|
attrlist));
|
|
}
|
|
|
|
|
|
class mdeletebyidInfo{
|
|
public:
|
|
mdeletebyidInfo(vector<Tuple*>* _relation,
|
|
TupleIdentifier* _tid,
|
|
ListExpr _type)
|
|
: relation(_relation), tid(_tid) {
|
|
type = new TupleType(_type);
|
|
firstcall = true;
|
|
}
|
|
|
|
~mdeletebyidInfo() {
|
|
type->DeleteIfAllowed();
|
|
}
|
|
|
|
Tuple* next() {
|
|
if(firstcall) {
|
|
firstcall = false;
|
|
if(!tid->IsDefined()){
|
|
return 0;
|
|
}
|
|
size_t index = tid->GetTid();
|
|
if(index==0 || index>relation->size()){
|
|
return 0;
|
|
}
|
|
Tuple* res = relation->at(index-1);
|
|
if(!res ) {
|
|
return 0;
|
|
}
|
|
(*relation)[index-1] = 0;
|
|
// overtake the attributes from the removed tuple
|
|
Tuple* newtup = new Tuple(type);
|
|
for(int i=0; i<res->GetNoAttributes(); i++) {
|
|
newtup->CopyAttribute(i,res,i);
|
|
}
|
|
Attribute* tidAttr = new TupleIdentifier(true,index);
|
|
newtup->PutAttribute(res->GetNoAttributes(), tidAttr);
|
|
res->DeleteIfAllowed();
|
|
return newtup;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
private:
|
|
vector<Tuple*>* relation;
|
|
TupleIdentifier* tid;
|
|
TupleType* type;
|
|
bool firstcall;
|
|
};
|
|
|
|
/*
|
|
|
|
7.15.2 Value Mapping Function of operator ~mdeletebyid~
|
|
|
|
*/
|
|
template<class T>
|
|
int mdeletebyidValMap (Word* args, Word& result,
|
|
int message, Word& local, Supplier s) {
|
|
|
|
mdeletebyidInfo* li = (mdeletebyidInfo*) local.addr;
|
|
|
|
switch (message) {
|
|
case OPEN: {
|
|
|
|
if(li){
|
|
delete li;
|
|
local.addr=0;
|
|
}
|
|
|
|
T* oN = (T*) args[0].addr;
|
|
|
|
MemoryRelObject* rel = getMemRel(oN);
|
|
if(!rel) { return 0; }
|
|
|
|
TupleIdentifier* tid = (TupleIdentifier*)(args[1].addr);
|
|
|
|
local.addr = new mdeletebyidInfo(rel->getmmrel(),
|
|
tid,
|
|
nl->Second(GetTupleResultType(s)));
|
|
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 0;
|
|
}
|
|
|
|
|
|
ValueMapping mdeletebyidVM[] = {
|
|
mdeletebyidValMap<Mem>,
|
|
mdeletebyidValMap<MPointer>
|
|
|
|
};
|
|
|
|
int mdeleteelect(ListExpr args){
|
|
ListExpr a = nl->First(args);
|
|
if(Mem::checkType(a)) return 0;
|
|
if(MPointer::checkType(a)) return 1;
|
|
return -1;
|
|
}
|
|
|
|
|
|
/*
|
|
7.15.4 Description of operator ~mdeletebyid~
|
|
|
|
*/
|
|
OperatorSpec mdeletepec(
|
|
"{mem(rel(tuple(x))), mpointer} x tid "
|
|
"-> stream(tuple(x@[TID:tid]))] ",
|
|
"_ mdeletebyid [_]",
|
|
"deletes the tuples possessing a given tupleid from the main memory "
|
|
"relation",
|
|
"query 'Staedte' mdeletebyid[[const tid value 5]] count"
|
|
);
|
|
|
|
/*
|
|
7.15.5 Instance of operator ~mdeletebyid~
|
|
|
|
*/
|
|
Operator mdeletebyidOp (
|
|
"mdeletebyid",
|
|
mdeletepec.getStr(),
|
|
2,
|
|
mdeletebyidVM,
|
|
mdeleteelect,
|
|
mdeletebyidTypeMap
|
|
);
|
|
|
|
|
|
/*
|
|
7.16 Operator ~mdeletedirect~
|
|
|
|
*/
|
|
ListExpr mdeletedirectTM(ListExpr args){
|
|
string err = "stream(tuple(X)) x (mem(rel(tuple(X)))) expected";
|
|
if(!nl->HasLength(args,2)){
|
|
return listutils::typeError("two arguments expected");
|
|
}
|
|
ListExpr stream = nl->First(args);
|
|
if(!Stream<Tuple>::checkType(stream)){
|
|
return listutils::typeError("first arg is not a tuple stream");
|
|
}
|
|
ListExpr mrel;
|
|
if(!getMemSubType(nl->Second(args),mrel)){
|
|
return listutils::typeError("Second arg is not a memory object");
|
|
}
|
|
ListExpr streamAttrList = nl->Second(nl->Second(stream));
|
|
ListExpr relAttrList = nl->Second(nl->Second(mrel));
|
|
if(!nl->Equal(streamAttrList, relAttrList)){
|
|
return listutils::typeError("attributes of stream and relation differ");
|
|
}
|
|
ListExpr append = nl->OneElemList(nl->TwoElemList(
|
|
nl->SymbolAtom("TID"),
|
|
listutils::basicSymbol<TupleIdentifier>()));
|
|
|
|
ListExpr resAttrList = listutils::concat( streamAttrList, append);
|
|
if(!listutils::isAttrList(resAttrList)){
|
|
return listutils::typeError("attribute TID already present. ");
|
|
}
|
|
return nl->TwoElemList(listutils::basicSymbol<Stream<Tuple> >(),
|
|
nl->TwoElemList(
|
|
listutils::basicSymbol<Tuple>(),
|
|
resAttrList));
|
|
|
|
}
|
|
|
|
|
|
class mdeletedirectInfo{
|
|
|
|
public:
|
|
mdeletedirectInfo(Word& _stream, vector<Tuple*>* _rel,
|
|
vector<Tuple*>* _saverel,
|
|
ListExpr resultTupleType):
|
|
stream(_stream), rel(_rel), saverel(_saverel) {
|
|
tt = new TupleType(resultTupleType);
|
|
stream.open();
|
|
}
|
|
|
|
~mdeletedirectInfo(){
|
|
stream.close();
|
|
tt->DeleteIfAllowed();
|
|
}
|
|
|
|
Tuple* next(){
|
|
Tuple* inTuple = stream.request();
|
|
if(!inTuple){
|
|
return 0;
|
|
}
|
|
TupleId tid = inTuple->GetTupleId();
|
|
if(tid>0 && tid <= rel->size()){
|
|
Tuple* victim = rel->at(tid-1);
|
|
if(victim){
|
|
rel->at(tid-1) = 0;
|
|
victim->DeleteIfAllowed();
|
|
}
|
|
}
|
|
Tuple* resTuple = createResTuple(inTuple);
|
|
inTuple->DeleteIfAllowed();
|
|
if(saverel){
|
|
resTuple->IncReference();
|
|
saverel->push_back(resTuple);
|
|
}
|
|
return resTuple;
|
|
}
|
|
|
|
private:
|
|
Stream<Tuple> stream;
|
|
vector<Tuple*>* rel;
|
|
vector<Tuple*>* saverel;
|
|
TupleType* tt;
|
|
|
|
Tuple* createResTuple(Tuple* inTuple){
|
|
Tuple* res = new Tuple(tt);
|
|
for(int i=0;i<inTuple->GetNoAttributes(); i++){
|
|
res->CopyAttribute(i,inTuple,i);
|
|
}
|
|
res->PutAttribute(inTuple->GetNoAttributes(),
|
|
new TupleIdentifier(true,inTuple->GetTupleId()));
|
|
return res;
|
|
}
|
|
|
|
};
|
|
|
|
|
|
template<class T>
|
|
int mdeletedirectVMT(Word* args, Word& result,
|
|
int message, Word& local, Supplier s) {
|
|
|
|
mdeletedirectInfo* li = (mdeletedirectInfo*) local.addr;
|
|
|
|
switch (message) {
|
|
case OPEN: {
|
|
if(li){
|
|
delete li;
|
|
local.addr=0;
|
|
}
|
|
|
|
T* oN = (T*) args[1].addr;
|
|
|
|
MemoryRelObject* rel = getMemRel(oN);
|
|
if(!rel) { return 0; }
|
|
|
|
local.addr = new mdeletedirectInfo(
|
|
args[0],
|
|
rel->getmmrel(),
|
|
0,
|
|
nl->Second(GetTupleResultType(s)));
|
|
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;
|
|
}
|
|
|
|
ValueMapping mdeletedirectVM[] = {
|
|
mdeletedirectVMT<Mem>,
|
|
mdeletedirectVMT<MPointer>
|
|
};
|
|
|
|
int mdeletedirectSelect(ListExpr args){
|
|
ListExpr s = nl->Second(args);
|
|
if(Mem::checkType(s)) return 0;
|
|
if(MPointer::checkType(s)) return 1;
|
|
return -1;
|
|
}
|
|
|
|
OperatorSpec mdeletedirectSpec(
|
|
"stream(tuple(X)) x MREL(tuple(X)) -> stream(tuple(X@(TID tid))),"
|
|
" MREL in {mem, mpointer} ",
|
|
"_ _ mdeletedirect",
|
|
"This function extracts the tuple ids from the incoming stream "
|
|
"and removes the tuples having this id from the main memory relation "
|
|
"which can be given as a string, a mem(rel) or an mpointer(mem(rel)). "
|
|
"The output are the incoming tuples extended by this id. Note that "
|
|
"the values of the result tuples have nothing to do with the values "
|
|
"stored in the relation. ",
|
|
"query ten feed mten mdeletedirect consume"
|
|
);
|
|
|
|
Operator mdeletedirectOp(
|
|
"mdeletedirect",
|
|
mdeletedirectSpec.getStr(),
|
|
2,
|
|
mdeletedirectVM,
|
|
mdeletedirectSelect,
|
|
mdeletedirectTM
|
|
);
|
|
|
|
/*
|
|
7.17 Operator ~mdeletedirectsave~
|
|
|
|
*/
|
|
ListExpr mdeletedirectsaveTM(ListExpr args){
|
|
string err = "stream(tuple(X)) x (mem(rel(tuple(X)))) x "
|
|
"mem(rel(tuple(X@TID))) expected";
|
|
if(!nl->HasLength(args,3)){
|
|
return listutils::typeError("three arguments expected");
|
|
}
|
|
ListExpr stream = nl->First(args);
|
|
if(!Stream<Tuple>::checkType(stream)){
|
|
return listutils::typeError("first arg is not a tuple stream");
|
|
}
|
|
|
|
ListExpr mrel;
|
|
if(!getMemSubType(nl->Second(args), mrel)){
|
|
return listutils::typeError("Second argument is not a memory object");
|
|
}
|
|
ListExpr streamAttrList = nl->Second(nl->Second(stream));
|
|
ListExpr relAttrList = nl->Second(nl->Second(mrel));
|
|
if(!nl->Equal(streamAttrList, relAttrList)){
|
|
return listutils::typeError("attributes of stream and relation differ");
|
|
}
|
|
ListExpr append = nl->OneElemList(nl->TwoElemList(
|
|
nl->SymbolAtom("TID"),
|
|
listutils::basicSymbol<TupleIdentifier>()));
|
|
|
|
ListExpr resAttrList = listutils::concat( streamAttrList, append);
|
|
if(!listutils::isAttrList(resAttrList)){
|
|
return listutils::typeError("attribute TID already present. ");
|
|
}
|
|
// check the saverel
|
|
ListExpr saverel;
|
|
if(!getMemSubType(nl->Third(args), saverel)){
|
|
return listutils::typeError("third arg is not a memory object");
|
|
}
|
|
ListExpr saveAttrList = nl->Second(nl->Second(saverel));
|
|
if(!nl->Equal(saveAttrList, resAttrList)){
|
|
return listutils::typeError("save relation scheme does not fit "
|
|
"the result scheme");
|
|
}
|
|
|
|
return nl->TwoElemList(listutils::basicSymbol<Stream<Tuple> >(),
|
|
nl->TwoElemList(
|
|
listutils::basicSymbol<Tuple>(),
|
|
resAttrList));
|
|
}
|
|
|
|
template<class T, class S>
|
|
int mdeletedirectsaveVMT(Word* args, Word& result,
|
|
int message, Word& local, Supplier s) {
|
|
|
|
mdeletedirectInfo* li = (mdeletedirectInfo*) local.addr;
|
|
|
|
switch (message) {
|
|
case OPEN: {
|
|
if(li){
|
|
delete li;
|
|
local.addr=0;
|
|
}
|
|
|
|
T* oN = (T*) args[1].addr;
|
|
|
|
MemoryRelObject* rel = getMemRel(oN);
|
|
if(!rel) { return 0; }
|
|
|
|
S* sN = (S*) args[2].addr;
|
|
|
|
MemoryRelObject* srel = getMemRel(sN);
|
|
if(!srel) { return 0; }
|
|
|
|
local.addr = new mdeletedirectInfo(
|
|
args[0],
|
|
rel->getmmrel(),
|
|
srel->getmmrel(),
|
|
nl->Second(GetTupleResultType(s)));
|
|
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;
|
|
}
|
|
|
|
ValueMapping mdeletedirectsaveVM[] = {
|
|
mdeletedirectsaveVMT<Mem, Mem>,
|
|
mdeletedirectsaveVMT<Mem, MPointer>,
|
|
mdeletedirectsaveVMT<MPointer, Mem>,
|
|
mdeletedirectsaveVMT<MPointer, MPointer>
|
|
};
|
|
|
|
int mdeletedirectsaveSelect(ListExpr args){
|
|
ListExpr s = nl->Second(args);
|
|
int n1 = 0;
|
|
if(Mem::checkType(s)) n1 = 0;
|
|
else if(MPointer::checkType(s)) n1 = 2;
|
|
|
|
s = nl->Third(args);
|
|
int n2 = 0;
|
|
if(Mem::checkType(s)) n2 = 0;
|
|
else if(MPointer::checkType(s)) n2 = 1;
|
|
|
|
return n1+n2;
|
|
}
|
|
|
|
OperatorSpec mdeletedirectsaveSpec(
|
|
"stream(tuple(X)) x MREL1(tuple(X)) x MREL2(rel(tuple(X@TID))"
|
|
" -> stream(tuple(X@(TID tid))), MREL1, MREL2 in { mem, mpointer}",
|
|
"_ _ _ mdeletedirectsave",
|
|
"This function extracts the tuple ids from the incoming stream "
|
|
"and removes the tuples having this id from the main memory relation "
|
|
"which can be given as a string, a mem(rel) or an mpointer(mem(rel)). "
|
|
"The output tuples are the incoming tuples extended by this id. "
|
|
"Beside giving the result tuples into the output stream, these "
|
|
"tuples are saved into an auxiliary relation given as the third argument. "
|
|
"Note that "
|
|
"the values of the result tuples have nothing to do with the values "
|
|
"stored in the relation. ",
|
|
"query ten feed mten mten_aux mdeletedirectsave consume"
|
|
);
|
|
|
|
Operator mdeletedirectsaveOp(
|
|
"mdeletedirectsave",
|
|
mdeletedirectsaveSpec.getStr(),
|
|
4,
|
|
mdeletedirectsaveVM,
|
|
mdeletedirectsaveSelect,
|
|
mdeletedirectsaveTM
|
|
);
|
|
|
|
|
|
/*
|
|
7.19 Operator ~mupdate~
|
|
|
|
*/
|
|
|
|
|
|
ListExpr mupdateTM(ListExpr args){
|
|
string err = "stream(tid) x {string, mem(rel) } x funlist expected";
|
|
if(!nl->HasLength(args,3)){
|
|
return listutils::typeError(err + " (wrong number of args)");
|
|
}
|
|
ListExpr stream = nl->First(args);
|
|
if(!Stream<TupleIdentifier>::checkType(stream)){
|
|
return listutils::typeError(err+ " (first arg is not a tid stream)");
|
|
}
|
|
ListExpr mem;
|
|
if(!getMemSubType(nl->Second(args),mem)){
|
|
return listutils::typeError("second argument is not a memory object");
|
|
}
|
|
|
|
if(!Relation::checkType(mem)){
|
|
return listutils::typeError("Second arg is not a memory relation");
|
|
}
|
|
ListExpr funList = nl->Third(args);
|
|
ListExpr tupleList = nl->Second(mem);
|
|
ListExpr attrList = nl->Second(tupleList);
|
|
|
|
ListExpr at;
|
|
if(listutils::findAttribute(attrList,"TID", at)){
|
|
return listutils::typeError("attribute TID already present");
|
|
}
|
|
|
|
|
|
// each element of funlist must be a list consisting
|
|
// of an attribute name in attrList and a function mapping
|
|
// tupleList into the attribute's type
|
|
set<string> used; // used attribute names
|
|
ListExpr appendList = nl->TheEmptyList();
|
|
ListExpr last;
|
|
bool first = true;
|
|
|
|
while(!nl->IsEmpty(funList)){
|
|
ListExpr fun = nl->First(funList);
|
|
funList = nl->Rest(funList);
|
|
if(!nl->HasLength(fun,2)){ //(name map)
|
|
return listutils::typeError("found element in typelist having "
|
|
"invalid length");
|
|
}
|
|
ListExpr name = nl->First(fun);
|
|
if(nl->AtomType(name)!=SymbolType){
|
|
return listutils::typeError("invalid attribute name");
|
|
}
|
|
string attr = nl->SymbolValue(nl->First(fun));
|
|
if(used.find(attr)!=used.end()){
|
|
return listutils::typeError("used attribute name " + attr + " twice");
|
|
}
|
|
used.insert(attr);
|
|
ListExpr map = nl->Second(fun);
|
|
ListExpr attrType;
|
|
int attrIndex = listutils::findAttribute(attrList, attr, attrType);
|
|
if(!attrIndex){
|
|
return listutils::typeError("Attribute " + attr
|
|
+ " not part of the relation");
|
|
}
|
|
if(first){
|
|
appendList = nl->OneElemList( nl->IntAtom(attrIndex-1));
|
|
last = appendList;
|
|
} else {
|
|
last = nl->Append(last, nl->IntAtom(attrIndex-1));
|
|
}
|
|
if(!listutils::isMap<1>(map)){
|
|
return listutils::typeError("invalid map definition");
|
|
}
|
|
if(!nl->Equal(nl->Second(map), tupleList)){
|
|
return listutils::typeError("function argument for " + attr +
|
|
+ " does not corresponds to the relation type");
|
|
}
|
|
if(!nl->Equal(nl->Third(map), attrType)){
|
|
return listutils::typeError("function result for " + attr
|
|
+ " does not corresponds to the attr type");
|
|
}
|
|
}
|
|
if(nl->IsEmpty(appendList)){
|
|
return listutils::typeError("function list is empty");
|
|
}
|
|
|
|
// create result tuple list
|
|
// step 1: overtake attributes
|
|
ListExpr tmp = attrList;
|
|
ListExpr resAttrList = nl->OneElemList(nl->First(tmp));
|
|
last = resAttrList;
|
|
tmp = nl->Rest(tmp);
|
|
while(!nl->IsEmpty(tmp)){
|
|
last = nl->Append(last, nl->First(tmp));
|
|
tmp = nl->Rest(tmp);
|
|
}
|
|
// append _old attributes
|
|
tmp = attrList;
|
|
while(!nl->IsEmpty(tmp)){
|
|
ListExpr attr = nl->First(tmp);
|
|
tmp = nl->Rest(tmp);
|
|
string newName = nl->SymbolValue(nl->First(attr))+"_old";
|
|
if(listutils::findAttribute(attrList,newName,at)){
|
|
return listutils::typeError("Attribute " + newName
|
|
+ "already known in tuple");
|
|
}
|
|
ListExpr na = nl->TwoElemList(nl->SymbolAtom(newName),
|
|
nl->Second(attr));
|
|
last = nl->Append(last, na);
|
|
}
|
|
// append TID
|
|
last = nl->Append(last, nl->TwoElemList( nl->SymbolAtom("TID"),
|
|
listutils::basicSymbol<TupleIdentifier>()));
|
|
|
|
tupleList = nl->TwoElemList(listutils::basicSymbol<Tuple>(),
|
|
resAttrList);
|
|
return nl->ThreeElemList(
|
|
nl->SymbolAtom(Symbols::APPEND()),
|
|
appendList,
|
|
nl->TwoElemList( listutils::basicSymbol<Stream<Tuple> >(),
|
|
tupleList));
|
|
}
|
|
|
|
|
|
class mupdateInfoN{
|
|
|
|
public:
|
|
mupdateInfoN(Word& _stream, vector<Tuple*>* _rel,
|
|
vector<int> _attrs,Supplier _funs,
|
|
ListExpr tt ) :stream(_stream),
|
|
rel(_rel), attrs(_attrs){
|
|
stream.open();
|
|
assert(qp->GetNoSons(_funs) == (int) attrs.size());
|
|
for(int i=0;i<qp->GetNoSons(_funs); i++){
|
|
Supplier s = qp->GetSupplier(qp->GetSupplier(_funs,i),1);
|
|
funs.push_back(s);
|
|
funargs.push_back(qp->Argument(s));
|
|
}
|
|
resType = new TupleType(tt);
|
|
}
|
|
~mupdateInfoN(){
|
|
stream.close();
|
|
resType->DeleteIfAllowed();
|
|
}
|
|
|
|
Tuple* next(){
|
|
TupleIdentifier* tid;
|
|
while( (tid=stream.request()) ){
|
|
if(tid->IsDefined()){
|
|
TupleId id = tid->GetTid();
|
|
if(id>0 && id <= rel->size()){
|
|
Tuple* res = rel->at(id-1);
|
|
if(res){
|
|
res->SetTupleId(id);
|
|
tid->DeleteIfAllowed();
|
|
return updateTuple(res);
|
|
}
|
|
}
|
|
}
|
|
tid->DeleteIfAllowed();
|
|
} // stream exhausted
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
Stream<TupleIdentifier> stream;
|
|
vector<Tuple*>* rel;
|
|
vector<int> attrs;
|
|
vector<Supplier> funs;
|
|
vector<ArgVectorPointer> funargs;
|
|
TupleType* resType;
|
|
Word funres;
|
|
|
|
Tuple* updateTuple(Tuple* orig){
|
|
Tuple* res = new Tuple(resType);
|
|
// copy all attributes twice
|
|
for(int i=0;i<orig->GetNoAttributes();i++){
|
|
res->CopyAttribute(i,orig,i);
|
|
res->CopyAttribute(i,orig, i + orig->GetNoAttributes());
|
|
}
|
|
res->PutAttribute(res->GetNoAttributes()-1,
|
|
new TupleIdentifier(true, orig->GetTupleId()));
|
|
|
|
// update according to the functions
|
|
for(size_t i=0;i<funs.size(); i++){
|
|
Supplier s = funs[i];
|
|
ArgVectorPointer a = funargs[i];
|
|
(*a)[0].setAddr(orig);
|
|
funres.addr = 0;
|
|
qp->Request(s,funres);
|
|
Attribute* resAttr = ((Attribute*)funres.addr)->Clone();
|
|
orig->PutAttribute(attrs[i], resAttr);
|
|
res->PutAttribute(attrs[i], resAttr->Copy());
|
|
}
|
|
return res;
|
|
|
|
}
|
|
};
|
|
|
|
|
|
|
|
template<class T>
|
|
int mupdateVMT(Word* args, Word& result,
|
|
int message, Word& local, Supplier s) {
|
|
|
|
mupdateInfoN* li = (mupdateInfoN*) local.addr;
|
|
switch(message){
|
|
case OPEN : {
|
|
if(li){
|
|
delete li;
|
|
local.addr = 0;
|
|
}
|
|
T* mrel = (T*) args[1].addr;
|
|
MemoryRelObject* rel = getMemRel(mrel);
|
|
if(!rel) {
|
|
return 0;
|
|
}
|
|
vector<int> attrs;
|
|
for(int i=3; i<qp->GetNoSons(s); i++){
|
|
attrs.push_back(((CcInt*)args[i].addr)->GetValue());
|
|
}
|
|
ListExpr tt = nl->Second(GetTupleResultType(s));
|
|
local.addr = new mupdateInfoN(args[0],
|
|
rel->getmmrel(),
|
|
attrs,
|
|
qp->GetSon(s,2), 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 -1;
|
|
}
|
|
|
|
ValueMapping mupdateVMN[] = {
|
|
mupdateVMT<Mem>,
|
|
mupdateVMT<MPointer>
|
|
};
|
|
|
|
int mupdateSelectN(ListExpr args){
|
|
return Mem::checkType(nl->Second(args))?0:1;
|
|
}
|
|
|
|
OperatorSpec mupdateSpecN(
|
|
"stream(tid) x MREL x funlist -> stream(tuple), "
|
|
"MREL in {mem, mpointer}",
|
|
"<stream> mupdate[ <memrel> ; funs]",
|
|
"Applies functions to the tuples in <memrel> specified by "
|
|
"their id's in the incomming stream and updates the tuples "
|
|
"in the relation. ",
|
|
"query mten mfeed filter[.No = 6] mupdate[mten, No : .No + 23] count"
|
|
);
|
|
|
|
|
|
Operator mupdateNOp(
|
|
"mupdate",
|
|
mupdateSpecN.getStr(),
|
|
2,
|
|
mupdateVMN,
|
|
mupdateSelectN,
|
|
mupdateTM
|
|
);
|
|
|
|
|
|
enum UpdateOp {
|
|
MUpdate,
|
|
MUpdateSave,
|
|
MUpdateByID
|
|
};
|
|
|
|
void update(vector<Tuple*>* relation, Tuple* res,
|
|
int changedIndex, Attribute* attr) {
|
|
|
|
vector<int> attrPos;
|
|
|
|
attrPos.push_back(changedIndex+1);
|
|
|
|
vector<Tuple*>::iterator it = relation->begin();
|
|
|
|
while(it != relation->end()) {
|
|
Tuple* tup = *it;
|
|
if(tup){
|
|
if(TupleComp::equal(res,tup,&attrPos)) {
|
|
tup->PutAttribute(changedIndex, attr->Clone());
|
|
return;
|
|
}
|
|
}
|
|
it++;
|
|
}
|
|
}
|
|
|
|
Tuple* copyAttributes(Tuple* res, TupleType* type) {
|
|
Tuple* tup = new Tuple(type);
|
|
assert(tup->GetNoAttributes() == 2 * res->GetNoAttributes() + 1);
|
|
for (int i=0; i<res->GetNoAttributes(); i++)
|
|
tup->PutAttribute(res->GetNoAttributes()+i,
|
|
res->GetAttribute(i)->Clone());
|
|
return tup;
|
|
}
|
|
|
|
/*
|
|
7.2 Operator ~mupdate~
|
|
|
|
The Operator ~mupdate~ updates all attributes in the tuples of a main
|
|
memory relation. The tuple to update are given by an input stream, the new
|
|
values of the attributes a calculated with a set of given functions.
|
|
The updated tuple, including a new attribute of type `tid`,
|
|
are appended to an output stream.
|
|
|
|
7.16.1 General Type Mapping Funktions for operator ~mupdate~ and
|
|
~mupdatesave~.
|
|
|
|
stream(tid) x mrel x funlist
|
|
|
|
stream(tid) x mrel x mrel x funlist
|
|
|
|
*/
|
|
template<bool save>
|
|
ListExpr mupdateTypeMap(ListExpr args) {
|
|
|
|
int noargs = save?4:3;
|
|
if(!nl->HasLength(args,noargs)){
|
|
return listutils::typeError("wrong number of arguments");
|
|
}
|
|
|
|
// process stream
|
|
ListExpr stream = nl->First(args);
|
|
if(!Stream<TupleIdentifier>::checkType(stream)){
|
|
return listutils::typeError("first argument must be a tuple id's");
|
|
}
|
|
|
|
// process second argument (mem(rel))
|
|
string errMsg;
|
|
ListExpr second;
|
|
if(!getMemSubType(nl->Second(args),second)) {
|
|
return listutils::typeError("2nd argument is not a memory object");
|
|
}
|
|
if(!Relation::checkType(second)) {
|
|
return listutils::typeError("second arg is not a memory relation");
|
|
}
|
|
ListExpr at;
|
|
if(listutils::findAttribute(nl->Second(nl->Second(second)),"TID",at)){
|
|
return listutils::typeError("Relation already contains a TID attribute");
|
|
}
|
|
|
|
ListExpr maps = save?nl->Fourth(args):nl->Third(args);
|
|
|
|
if( (nl->AtomType(maps)!=NoAtom)
|
|
|| nl->IsEmpty(maps)){
|
|
return listutils::typeError("last arg must be a non-empty list of maps");
|
|
}
|
|
|
|
// check maps
|
|
ListExpr tuple = nl->Second(second);
|
|
ListExpr attrList = nl->Second(tuple);
|
|
|
|
ListExpr indexList = nl->TheEmptyList();
|
|
ListExpr lastIndex = indexList;
|
|
|
|
// create the result list as a copy from attrlist
|
|
ListExpr newAttrList = nl->OneElemList(nl->First(attrList));
|
|
ListExpr last = newAttrList;
|
|
ListExpr tmp = nl->Rest(attrList);
|
|
while(!nl->IsEmpty(tmp)){
|
|
last = nl->Append(last,nl->First(tmp));
|
|
tmp = nl->Rest(tmp);
|
|
}
|
|
// append the same attributes with additional _old
|
|
tmp = attrList;
|
|
while(!nl->IsEmpty(tmp)){
|
|
ListExpr a = nl->First(tmp);
|
|
tmp = nl->Rest(tmp);
|
|
last = nl->Append(last, nl->TwoElemList(
|
|
nl->SymbolAtom(
|
|
nl->SymbolValue(nl->First(a))+"_old"),
|
|
nl->Second(a)));
|
|
}
|
|
last = nl->Append(last,nl->TwoElemList(
|
|
nl->SymbolAtom("TID"),
|
|
listutils::basicSymbol<TupleIdentifier>()));
|
|
if(!listutils::isAttrList(newAttrList)){
|
|
return listutils::typeError("Found name conflict in result type");
|
|
}
|
|
|
|
set<string> used;
|
|
while(!nl->IsEmpty(maps)){
|
|
ListExpr map = nl->First(maps);
|
|
maps = nl->Rest(maps);
|
|
if(!nl->HasLength(map,2)){ // (name map)
|
|
return listutils::typeError("funlist contains not a named function");
|
|
}
|
|
if( !listutils::isSymbol(nl->First(map))
|
|
||!listutils::isMap<1>(nl->Second(map))){
|
|
return listutils::typeError("funlist contains not a named function");
|
|
}
|
|
string attrName = nl->SymbolValue(nl->First(map));
|
|
if(used.find(attrName)!=used.end()){
|
|
return listutils::typeError("used " + attrName + " twice");
|
|
}
|
|
used.insert(attrName);
|
|
if(listutils::findAttribute(attrList, attrName+"_old", at)){
|
|
return listutils::typeError(attrName
|
|
+ "_old already part of the relation");
|
|
}
|
|
int index = listutils::findAttribute(attrList, attrName, at);
|
|
if(index==0){
|
|
return listutils::typeError( "Attribute " + attrName
|
|
+ " not part of the relation");
|
|
}
|
|
ListExpr fun = nl->Second(map);
|
|
if(!nl->Equal(nl->Second(fun), tuple)){
|
|
return listutils::typeError("function argument for " + attrName
|
|
+ " differs from the tuple type");
|
|
}
|
|
if(!nl->Equal(nl->Third(fun), at)){
|
|
return listutils::typeError("function result for " + attrName
|
|
+ " differs from the attribute type");
|
|
}
|
|
// checks successful, extend lists
|
|
if(nl->IsEmpty(indexList)){
|
|
indexList = nl->OneElemList(nl->IntAtom(index-1));
|
|
lastIndex = indexList;
|
|
} else {
|
|
lastIndex = nl->Append(lastIndex,nl->IntAtom(index-1));
|
|
}
|
|
}
|
|
ListExpr newTuple = nl->TwoElemList(
|
|
listutils::basicSymbol<Tuple>(),
|
|
newAttrList);
|
|
|
|
|
|
if(save){ // check third argument
|
|
ListExpr auxRel;
|
|
if(!getMemSubType(nl->Third(args),auxRel)){
|
|
return listutils::typeError("third arg is not a memory object");
|
|
}
|
|
if(!Relation::checkType(auxRel)){
|
|
return listutils::typeError("third arg is not a memory relation");
|
|
}
|
|
if(!nl->Equal(nl->Second(auxRel), newTuple)){
|
|
return listutils::typeError("auxiliarary relation has another type "
|
|
"than the result");
|
|
}
|
|
}
|
|
|
|
return nl->ThreeElemList(
|
|
nl->SymbolAtom(Symbols::APPEND()),
|
|
indexList,
|
|
nl->TwoElemList(
|
|
listutils::basicSymbol<Stream<Tuple> >(),
|
|
newTuple));
|
|
}
|
|
|
|
class mupdateInfo {
|
|
public:
|
|
mupdateInfo(Word& _stream,
|
|
vector<Tuple*>* _mainRelation,
|
|
bool _flob,
|
|
Supplier _funs,
|
|
vector<Tuple*>* _auxRelation,
|
|
vector<int>& _indexes,
|
|
ListExpr _type) :
|
|
stream(_stream), mainRelation(_mainRelation),
|
|
flob(_flob), auxRelation(_auxRelation),
|
|
indexes(_indexes) {
|
|
type = new TupleType(_type);
|
|
stream.open();
|
|
for(int i=0;i<qp->GetNoSons(_funs); i++){
|
|
Supplier s = qp->GetSupplier(qp->GetSupplier(_funs,i),1);
|
|
ArgVectorPointer p = qp->Argument(s);
|
|
funs.push_back(s);
|
|
funargs.push_back(p);
|
|
}
|
|
assert(indexes.size()==funs.size());
|
|
|
|
}
|
|
|
|
|
|
~mupdateInfo(){
|
|
stream.close();
|
|
type->DeleteIfAllowed();
|
|
}
|
|
|
|
Tuple* next() {
|
|
TupleIdentifier* t;
|
|
while( (t=stream.request())){
|
|
if(!t->IsDefined()){
|
|
t->DeleteIfAllowed();
|
|
} else {
|
|
TupleId id = t->GetTid();
|
|
t->DeleteIfAllowed();
|
|
if(id>0 && id <=mainRelation->size()){
|
|
Tuple* tuple = mainRelation->at(id-1);
|
|
if(tuple){
|
|
return createResultTuple(id, tuple);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
private:
|
|
Stream<TupleIdentifier> stream;
|
|
vector<Tuple*>* mainRelation;
|
|
bool flob;
|
|
vector<Tuple*>* auxRelation;
|
|
vector<int> indexes;
|
|
vector<Supplier> funs;
|
|
vector<ArgVectorPointer> funargs;
|
|
TupleType* type;
|
|
Word v;
|
|
|
|
Tuple* createResultTuple(TupleId id, Tuple* tuple){
|
|
Tuple* res = new Tuple(type);
|
|
// copy all attributes twice into the new tuple
|
|
for(int i=0;i<tuple->GetNoAttributes(); i++){
|
|
res->CopyAttribute(i,tuple,i);
|
|
res->CopyAttribute(i,tuple, i + tuple->GetNoAttributes());
|
|
}
|
|
// put tid into tuple
|
|
res->PutAttribute(res->GetNoAttributes()-1,
|
|
new TupleIdentifier(true,id));
|
|
res->SetTupleId(id);
|
|
// update attributes
|
|
for(size_t i=0;i<funs.size();i++){
|
|
(*(funargs[i]))[0] = tuple;
|
|
v.addr = 0;
|
|
qp->Request(funs[i],v);
|
|
Attribute* newAttr = ((Attribute*)v.addr)->Clone();
|
|
if(flob){
|
|
newAttr->bringToMemory();
|
|
}
|
|
res->PutAttribute(indexes[i], newAttr); // put to res
|
|
tuple->PutAttribute(indexes[i], newAttr->Copy()); // update relation
|
|
}
|
|
// save if necessary
|
|
if(auxRelation){
|
|
res->IncReference();
|
|
auxRelation->push_back(res);
|
|
}
|
|
return res;
|
|
}
|
|
};
|
|
|
|
|
|
/*
|
|
|
|
7.16.3 Value Mapping Function of operator ~mupdate~
|
|
|
|
*/
|
|
template<class T, class S, bool save>
|
|
int mupdateValMap (Word* args, Word& result,
|
|
int message, Word& local, Supplier s) {
|
|
|
|
mupdateInfo* li = (mupdateInfo*) local.addr;
|
|
|
|
switch (message) {
|
|
|
|
case OPEN : {
|
|
|
|
if(li) {
|
|
delete li;
|
|
local.addr=0;
|
|
}
|
|
T* oN = (T*) args[1].addr;
|
|
MemoryRelObject* rel = getMemRel(oN);
|
|
ListExpr tt = nl->Second(GetTupleResultType(s));
|
|
int funindex = 2;
|
|
vector<Tuple*>* auxRel = 0;
|
|
if(save){
|
|
funindex = 3;
|
|
S* aRel = (S*) args[2].addr;
|
|
MemoryRelObject* arel = getMemRel(aRel);
|
|
auxRel = arel->getmmrel();
|
|
}
|
|
|
|
vector<int> indexes;
|
|
for(int i=funindex+1;i<qp->GetNoSons(s);i++){
|
|
indexes.push_back(((CcInt*)args[i].addr)->GetValue());
|
|
}
|
|
local.addr = new mupdateInfo(args[0], // stream
|
|
rel->getmmrel(), // main relation
|
|
rel->hasflob(), // flob?
|
|
qp->GetSon(s,funindex), // funlist
|
|
auxRel, // auxiliary relation
|
|
indexes, // attribute indexes
|
|
tt); // result tuple type
|
|
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 0;
|
|
}
|
|
|
|
ValueMapping mupdateVM[] = {
|
|
mupdateValMap<Mem, Mem, false>,
|
|
mupdateValMap<MPointer, Mem, false>
|
|
};
|
|
|
|
int mupdateSelect(ListExpr args){
|
|
ListExpr t = nl->Second(args);
|
|
if(Mem::checkType(t)) return 0;
|
|
if(MPointer::checkType(t)) return 1;
|
|
return -1;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
7.16.4 Description of operator ~mupdate~
|
|
|
|
*/
|
|
OperatorSpec mupdateSpec(
|
|
"stream(tuple(x)) x MREL x [(a1, (tuple(x) -> d1)) "
|
|
"... (an, (tuple(x) -> dn))] -> "
|
|
"stream(tuple(x @ [x1_old t1] @...[xn_old tn] @ [TID tid]))),"
|
|
" MREL in {mem, mpointer}",
|
|
"_ mupdate[_; funlist] implicit parameter tuple type TUPLE",
|
|
"updates the tuple of a stream in an "
|
|
"existing main memory relation",
|
|
"query Staedte feed filter[.SName = 'Hannover'] "
|
|
"mupdate['Staedte';Bev: .Bev + 1000] count"
|
|
);
|
|
|
|
/*
|
|
7.16.5 Instance of operator ~mupdate~
|
|
|
|
*/
|
|
Operator mupdateOp (
|
|
"mupdate",
|
|
mupdateSpec.getStr(),
|
|
2,
|
|
mupdateVM,
|
|
mupdateSelect,
|
|
mupdateTypeMap<false>
|
|
);
|
|
|
|
|
|
ValueMapping mupdatesaveVM[] = {
|
|
mupdateValMap<Mem, Mem, true>,
|
|
mupdateValMap<Mem, MPointer, true>,
|
|
mupdateValMap<MPointer, Mem, true>,
|
|
mupdateValMap<MPointer, MPointer, true>
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int mupdatesaveSelect(ListExpr args){
|
|
int n1 = Mem::checkType(nl->Second(args))?0:2;
|
|
int n2 = Mem::checkType(nl->Third(args))?0:1;
|
|
return n1+n2;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
7.17.4 Description of operator ~mupdatesave~
|
|
|
|
*/
|
|
OperatorSpec mupdatesaveSpec(
|
|
"stream(tuple(x)) x MREL1 "
|
|
"x [(a1, (tuple(x) -> d1)) ... (an,(tuple(x) -> dn))] "
|
|
"x MREL2 -> "
|
|
"stream(tuple(x @ [x1_old t1] @...[xn_old tn] @ [TID tid]))),"
|
|
"MREL1, MREL2 in {mem,mpointer}",
|
|
"_ mupdatesave[_,_; funlist] implicit parameter tuple type TUPLE",
|
|
"updates the tuple of a stream in an "
|
|
"existing main memory relation and saves the tuples of the output "
|
|
"stream in an additional main memory relation",
|
|
"query Staedte feed filter[.SName = 'Hannover'] "
|
|
"mupdatesave['Staedte','Stadt';Bev: .Bev + 1000] count"
|
|
);
|
|
|
|
/*
|
|
7.17.5 Instance of operator ~mupdatesave~
|
|
|
|
*/
|
|
Operator mupdatesaveOp (
|
|
"mupdatesave",
|
|
mupdatesaveSpec.getStr(),
|
|
4,
|
|
mupdatesaveVM,
|
|
mupdatesaveSelect,
|
|
mupdateTypeMap<true>
|
|
);
|
|
|
|
|
|
/*
|
|
7.18 Operator ~mupdatebyid~
|
|
|
|
The Operator ~mupdatebyid~ updates the tuple with the given tupleidentifier
|
|
in a main memory relation, using functions to calculate the new attribute
|
|
values. The updated tuple is returned in an output stream with all attributes
|
|
copied and extended by the suffix 'old'. Also an attribute of type 'tid' is
|
|
added.
|
|
|
|
7.18.1 Type Mapping Function of operator
|
|
|
|
|
|
*/
|
|
ListExpr mupdatebyidTypeMap(ListExpr args) {
|
|
if(nl->ListLength(args) != 3) {
|
|
return listutils::typeError("wrong number of arguments");
|
|
}
|
|
|
|
// process first arg
|
|
ListExpr first;
|
|
if(!getMemSubType(nl->First(args), first)){
|
|
return listutils::typeError("first argument is not a memory object");
|
|
}
|
|
if(!Relation::checkType(first)){
|
|
return listutils::typeError("first arg is not a memory relation");
|
|
}
|
|
|
|
// process second arg (tid)
|
|
ListExpr second = nl->Second(args);
|
|
if(!listutils::isSymbol(second,TupleIdentifier::BasicType())){
|
|
return listutils::typeError("second argument must be a tid");
|
|
}
|
|
|
|
// process update function
|
|
ListExpr map = nl->Third(args);
|
|
|
|
// argument is not a map
|
|
ListExpr maprest = map;
|
|
if(nl->ListLength(maprest<1)) {
|
|
return listutils::typeError("arg must be a list of maps");
|
|
}
|
|
int noAttrs = nl->ListLength(maprest);
|
|
|
|
|
|
// copy all original attributes to resAttrList
|
|
ListExpr inAttrList = nl->Second(nl->Second(first));
|
|
ListExpr resAttrList = nl->TheEmptyList();
|
|
ListExpr resAttrListLast= nl->TheEmptyList();
|
|
bool firstcall = true;
|
|
while(!nl->IsEmpty(inAttrList)){
|
|
ListExpr attr = nl->First(inAttrList);
|
|
inAttrList = nl->Rest(inAttrList);
|
|
if(firstcall){
|
|
resAttrList = nl->OneElemList(attr);
|
|
resAttrListLast = resAttrList;
|
|
firstcall = false;
|
|
} else {
|
|
resAttrListLast = nl->Append(resAttrListLast, attr);
|
|
}
|
|
}
|
|
|
|
// Go through all functions
|
|
ListExpr mapfirst, mapsecond;
|
|
ListExpr attrType;
|
|
ListExpr indices=nl->TheEmptyList(), indicescurrent = nl->TheEmptyList();
|
|
|
|
firstcall = true;
|
|
while (!(nl->IsEmpty(maprest))) {
|
|
map = nl->First(maprest);
|
|
maprest = nl->Rest(maprest);
|
|
mapfirst = nl->First(map);
|
|
mapsecond = nl->Second(map);
|
|
|
|
// check if argument map is a function
|
|
if(!listutils::isMap<1>(mapsecond)){
|
|
return listutils::typeError("not a map found");
|
|
}
|
|
if(!nl->Equal(nl->Second(first),nl->Second(mapsecond))) {
|
|
return listutils::typeError("argument of map is wrong");
|
|
}
|
|
|
|
// check for valid attribute name in function
|
|
if(!listutils::isSymbol(mapfirst)){
|
|
return listutils::typeError("not a valid attribute name:" +
|
|
nl->ToString(mapfirst));
|
|
}
|
|
string argstr;
|
|
int attrIndex;
|
|
nl->WriteToString(argstr, mapfirst);
|
|
attrIndex = listutils::findAttribute(nl->Second(nl->Second(first)),
|
|
argstr, attrType);
|
|
if(attrIndex==0){
|
|
return listutils::typeError("attribute " + argstr + " not known");
|
|
}
|
|
if(!nl->Equal(attrType, nl->Third(mapsecond))){
|
|
return listutils::typeError("result of the map and attribute"
|
|
" type differ");
|
|
}
|
|
|
|
// construct list with all indices of the changed attributes
|
|
// in the inputstream to be appended to the resultstream
|
|
if(firstcall) {
|
|
indices = nl->OneElemList(nl->IntAtom(attrIndex));
|
|
indicescurrent = indices;
|
|
firstcall = false;
|
|
} else {
|
|
indicescurrent = nl->Append(indicescurrent,
|
|
nl->IntAtom(attrIndex));
|
|
}
|
|
argstr += "_old";
|
|
ListExpr newAttr = nl->TwoElemList( nl->SymbolAtom(argstr),
|
|
attrType);
|
|
resAttrListLast= nl->Append(resAttrListLast, newAttr);
|
|
}
|
|
|
|
|
|
// append TID as the last attribute for result
|
|
ListExpr newAttr = nl->TwoElemList(nl->SymbolAtom("TID"),
|
|
listutils::basicSymbol<TupleIdentifier>());
|
|
resAttrListLast = nl->Append(resAttrListLast, newAttr);
|
|
|
|
|
|
ListExpr resType = nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()),
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom(Tuple::BasicType()),
|
|
resAttrList));
|
|
|
|
|
|
ListExpr res = nl->ThreeElemList(nl->SymbolAtom(Symbols::APPEND()),
|
|
nl->TwoElemList(nl->IntAtom(noAttrs),
|
|
indices),
|
|
resType);
|
|
return res;
|
|
|
|
}
|
|
|
|
class mupdatebyidInfo {
|
|
public:
|
|
mupdatebyidInfo(vector<Tuple*>* _relation,
|
|
TupleIdentifier* _tid,
|
|
Word& _funlist,
|
|
Word& _indices,
|
|
TupleType* _type)
|
|
: relation(_relation), tid(_tid),
|
|
funlist(_funlist),
|
|
indices(_indices),
|
|
type(_type) {
|
|
type->IncReference();
|
|
firstcall = true;
|
|
}
|
|
|
|
~mupdatebyidInfo(){
|
|
type->DeleteIfAllowed();
|
|
}
|
|
|
|
Tuple* next() {
|
|
// returns only a single tuple
|
|
if(!firstcall) return 0;
|
|
firstcall = false;
|
|
// special case tid undefined
|
|
if(!tid->IsDefined()){
|
|
return 0;
|
|
}
|
|
TupleId id = tid->GetTid();
|
|
// special case tid ouside the allowed range
|
|
if(id<1 || id>relation->size()){
|
|
return 0;
|
|
}
|
|
|
|
Tuple* orig = relation->at(id-1);
|
|
// special case: tuple already removed
|
|
if(!orig) return 0;
|
|
return computeResult(orig);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
vector<Tuple*>* relation;
|
|
TupleIdentifier* tid;
|
|
Word funlist;
|
|
Word indices;
|
|
TupleType* type;
|
|
bool firstcall;
|
|
Word elem, value;
|
|
|
|
|
|
Tuple* computeResult(Tuple* orig) {
|
|
|
|
Tuple* res = new Tuple(type);
|
|
|
|
int noAttr = res->GetNoAttributes() - (orig->GetNoAttributes() + 1);
|
|
|
|
// copy all attributes from orig to res
|
|
for(int i=0;i<orig->GetNoAttributes();i++){
|
|
res->CopyAttribute(i,orig,i);
|
|
}
|
|
|
|
// collect changed indexes and
|
|
// computes attributes into vectors
|
|
|
|
Word Index;
|
|
vector<int> indexv;
|
|
vector<Attribute*> attrv;
|
|
|
|
|
|
for(int i=0;i<noAttr;i++){
|
|
// get the attribute id
|
|
Supplier son = qp->GetSupplier(indices.addr,i);
|
|
qp->Request(son,Index);
|
|
int index = ((CcInt*)Index.addr)->GetIntval()-1;
|
|
res->CopyAttribute(index, orig, orig->GetNoAttributes()+i);
|
|
|
|
Attribute* replacement = computeFun(orig, i);
|
|
indexv.push_back(index);
|
|
attrv.push_back(replacement);
|
|
}
|
|
|
|
// replace attributes in orig and result
|
|
for(int i=0;i<noAttr; i++){
|
|
orig->PutAttribute(indexv[i], attrv[i]);
|
|
res->PutAttribute(indexv[i], attrv[i]->Copy());
|
|
}
|
|
// finally copy the tid into result and change its tid
|
|
res->PutAttribute(res->GetNoAttributes()-1, tid->Copy());
|
|
res->SetTupleId(tid->GetTid());
|
|
|
|
return res;
|
|
}
|
|
|
|
Attribute* computeFun( Tuple* orig, int funNo){
|
|
Supplier funs = funlist.addr;
|
|
Supplier s1 = qp->GetSupplier(funs, funNo);
|
|
Supplier fun = qp->GetSupplier(s1, 1);
|
|
ArgVectorPointer funargs = qp->Argument(fun);
|
|
((*funargs)[0]).setAddr(orig);
|
|
Word value;
|
|
qp->Request(fun,value);
|
|
return ((Attribute*)value.addr)->Clone();
|
|
}
|
|
};
|
|
|
|
|
|
/*
|
|
|
|
7.18.3 Value Mapping Function of operator ~mupdatebyid~
|
|
|
|
*/
|
|
template<class T>
|
|
int mupdatebyidValueMap (Word* args, Word& result,
|
|
int message, Word& local, Supplier s) {
|
|
|
|
mupdatebyidInfo* li = (mupdatebyidInfo*) local.addr;
|
|
TupleType* tt = (TupleType*) qp->GetLocal2(s).addr;
|
|
|
|
switch (message) {
|
|
|
|
case INIT: {
|
|
tt = new TupleType(nl->Second(GetTupleResultType(s)));
|
|
qp->GetLocal2(s).addr=tt;
|
|
return 0;
|
|
}
|
|
|
|
case FINISH: {
|
|
if(tt){
|
|
tt->DeleteIfAllowed();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
case OPEN : {
|
|
if(li){
|
|
delete li;
|
|
local.addr=0;
|
|
}
|
|
|
|
T* oN = (T*) args[0].addr;
|
|
MemoryRelObject* rel = getMemRel(oN);
|
|
|
|
if(!rel) {return 0;}
|
|
|
|
TupleIdentifier* tid = (TupleIdentifier*)(args[1].addr);
|
|
//int noAttr = ((CcInt*) args[3].addr)->GetValue();
|
|
local.addr = new mupdatebyidInfo(rel->getmmrel(),tid,args[2],
|
|
args[4],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 0;
|
|
|
|
}
|
|
|
|
ValueMapping mupdatebyidVM[] = {
|
|
mupdatebyidValueMap<Mem>,
|
|
mupdatebyidValueMap<MPointer>
|
|
};
|
|
|
|
int mupdatebyidSelect(ListExpr args){
|
|
return Mem::checkType(nl->First(args))?0:1;
|
|
}
|
|
|
|
/*
|
|
7.18.4 Description of operator ~mupdatebyid~
|
|
|
|
*/
|
|
OperatorSpec mupdatebyidSpec(
|
|
"MREL x (tid) x "
|
|
"[(a1, (tuple(x) -> d1)) ... (an,(tuple(x) -> dn))] "
|
|
"-> stream(tuple(x @ [x1_old t1] @...[xn_old tn] @ [TID tid]))),"
|
|
" MREL in{mem, mpointer}",
|
|
"_ mupdatebyid[_; funlist] implicit parameter tuple type MTUPLE",
|
|
"updates the tuple with the given tupleidentifier from "
|
|
"a main memory relation",
|
|
"query Staedte feed filter[.SName = 'Hannover'] "
|
|
"mupdate['Staedte'; Bev: .Bev + 1000] count"
|
|
);
|
|
|
|
/*
|
|
|
|
7.18.5 Instance of operator ~mupdatebyid~
|
|
|
|
*/
|
|
Operator mupdatebyidOp (
|
|
"mupdatebyid",
|
|
mupdatebyidSpec.getStr(),
|
|
2,
|
|
mupdatebyidVM,
|
|
mupdatebyidSelect,
|
|
mupdatebyidTypeMap
|
|
);
|
|
|
|
/*
|
|
7.19 Operator ~mupdatedirect2~
|
|
|
|
*/
|
|
ListExpr mupdatedirect2TM(ListExpr args){
|
|
if(!nl->HasLength(args,4)){
|
|
return listutils::typeError("4 arguments expected");
|
|
}
|
|
ListExpr stream = nl->First(args);
|
|
if(!Stream<Tuple>::checkType(stream)){
|
|
return listutils::typeError("first argument is not a tuple stream");
|
|
}
|
|
ListExpr tt1 = nl->Second(stream);
|
|
|
|
ListExpr mrel;
|
|
if(!getMemSubType(nl->Second(args),mrel)){
|
|
return listutils::typeError("second arg is not a memory object");
|
|
}
|
|
|
|
if(!Relation::checkType(mrel)){
|
|
return listutils::typeError("Second argument is not a memory relation");
|
|
}
|
|
|
|
ListExpr Attr = nl->Third(args);
|
|
if(nl->AtomType(Attr) != SymbolType){
|
|
return listutils::typeError("Third arg is not a valid attribute name");
|
|
}
|
|
ListExpr funlist = nl->Fourth(args);
|
|
if(nl->AtomType(funlist) != NoAtom){
|
|
return listutils::typeError("fourth arg is not a list of functions");
|
|
}
|
|
int noFuns = nl->ListLength(funlist);
|
|
if(noFuns < 1){
|
|
return listutils::typeError("at least 1 function required");
|
|
}
|
|
ListExpr type;
|
|
ListExpr attrList = nl->Second(nl->Second(mrel));
|
|
string attrName = nl->SymbolValue(Attr);
|
|
|
|
int tidIndex = listutils::findAttribute(nl->Second(nl->Second(stream)),
|
|
attrName, type);
|
|
if(!tidIndex){
|
|
return listutils::typeError("Attribute " + attrName
|
|
+ " not part of the tuple stream");
|
|
}
|
|
if(!TupleIdentifier::checkType(type)){
|
|
return listutils::typeError("Attribute " + attrName
|
|
+ " not of type tid");
|
|
}
|
|
|
|
|
|
ListExpr tt2 = nl->Second(mrel);
|
|
attrList = nl->Second(tt2);
|
|
|
|
ListExpr funindexes=nl->TheEmptyList();
|
|
ListExpr last = nl->TheEmptyList();
|
|
set<int> used;
|
|
bool first = true;
|
|
while(!nl->IsEmpty(funlist)){
|
|
ListExpr namedFun = nl->First(funlist);
|
|
funlist = nl->Rest(funlist);
|
|
if(!nl->HasLength(namedFun,2)){
|
|
return listutils::typeError("invalid named function in list");
|
|
}
|
|
Attr = nl->First(namedFun);
|
|
if(nl->AtomType(Attr) != SymbolType){
|
|
return listutils::typeError("invalid function name found");
|
|
}
|
|
attrName = nl->SymbolValue(Attr);
|
|
int attrIndex = listutils::findAttribute(attrList, attrName, type);
|
|
if(used.find(attrIndex)!=used.end()){
|
|
return listutils::typeError("found more than one function for "
|
|
+ attrName);
|
|
}
|
|
used.insert(attrIndex);
|
|
if(!attrIndex){
|
|
return listutils::typeError("Attribute " + attrName
|
|
+ " not found in Relation");
|
|
}
|
|
ListExpr fun = nl->Second(namedFun);
|
|
if(!listutils::isMap<2>(fun)){
|
|
return listutils::typeError("no binary fun for attribute" + attrName);
|
|
}
|
|
// check that the funtion argument ist the relation tuple
|
|
if(!nl->Equal(tt1, nl->Second(fun))){
|
|
return listutils::typeError("first function argument and tuple"
|
|
" type of stream differ");
|
|
}
|
|
if(!nl->Equal(tt2, nl->Third(fun))){
|
|
return listutils::typeError("second function argument and tuple"
|
|
" type of relation differ");
|
|
}
|
|
// check that the function result corresponds to the attribute type
|
|
if(!nl->Equal(type, nl->Fourth(fun))){
|
|
return listutils::typeError("function result and type of "
|
|
+ attrName + " differ");
|
|
}
|
|
// append attrIndex to indexes
|
|
if(first){
|
|
funindexes = nl->OneElemList(nl->IntAtom(attrIndex - 1 ));
|
|
last = funindexes;
|
|
first = false;
|
|
} else {
|
|
last = nl->Append(last,nl->IntAtom(attrIndex - 1));
|
|
}
|
|
}
|
|
|
|
ListExpr resType = nl->TwoElemList(
|
|
listutils::basicSymbol<Stream<Tuple> >(),
|
|
tt2);
|
|
|
|
ListExpr res = nl->ThreeElemList(
|
|
nl->SymbolAtom(Symbols::APPEND()),
|
|
nl->ThreeElemList(nl->IntAtom(tidIndex-1),
|
|
nl->IntAtom(noFuns),
|
|
funindexes),
|
|
resType
|
|
);
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
class mupdatedirect2LocalInfo{
|
|
|
|
public:
|
|
mupdatedirect2LocalInfo(Word _stream, vector<Tuple*>* _relation,
|
|
int _tidIndex, Word _funs, vector<int>& _funindexes):
|
|
stream(_stream), relation(_relation), tidIndex(_tidIndex),
|
|
funindexes(_funindexes)
|
|
{
|
|
|
|
stream.open();
|
|
for(size_t i=0;i<_funindexes.size();i++){
|
|
Supplier s1 = qp->GetSupplier(_funs.addr,i);
|
|
Supplier fun = qp->GetSupplier(s1,1);
|
|
ArgVectorPointer avp = qp->Argument(fun);
|
|
funs.push_back(fun);
|
|
funargs.push_back(avp);
|
|
}
|
|
}
|
|
~mupdatedirect2LocalInfo(){
|
|
stream.close();
|
|
}
|
|
|
|
Tuple* next(){
|
|
Tuple* tuple = stream.request();
|
|
while(tuple) {
|
|
TupleIdentifier* Tid = (TupleIdentifier*)tuple->GetAttribute(tidIndex);
|
|
if(Tid->IsDefined()){
|
|
TupleId tid = Tid->GetTid();
|
|
if((tid > 0) && (tid <= relation->size())){
|
|
Tuple* relTuple = relation->at(tid-1);
|
|
if(relTuple){
|
|
Tuple* resTuple = updateTuple(tuple, relTuple);
|
|
tuple->DeleteIfAllowed();
|
|
resTuple->SetTupleId(tid);
|
|
return resTuple;
|
|
}
|
|
}
|
|
}
|
|
tuple->DeleteIfAllowed();
|
|
tuple = stream.request();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
private:
|
|
Stream<Tuple> stream;
|
|
vector<Tuple*>* relation;
|
|
int tidIndex;
|
|
vector<int> funindexes;
|
|
vector<Supplier> funs;
|
|
vector<ArgVectorPointer> funargs;
|
|
Word result;
|
|
|
|
Tuple* updateTuple(Tuple* streamTuple, Tuple* relTuple){
|
|
vector<Attribute*> uattrs;
|
|
for(size_t i=0;i<funs.size();i++){
|
|
ArgVectorPointer avp = funargs[i];
|
|
(*avp)[0].addr = streamTuple;
|
|
(*avp)[1].addr = relTuple;
|
|
qp->Request(funs[i], result);
|
|
uattrs.push_back( ((Attribute*) result.addr)->Clone());
|
|
}
|
|
for(size_t i=0;i<funindexes.size();i++){
|
|
relTuple->PutAttribute(funindexes[i], uattrs[i]);
|
|
}
|
|
Tuple* resTuple = new Tuple(relTuple->GetTupleType());
|
|
for(int i=0;i<relTuple->GetNoAttributes();i++){
|
|
resTuple->CopyAttribute(i,relTuple,i);
|
|
}
|
|
return resTuple;
|
|
}
|
|
};
|
|
|
|
|
|
|
|
template<class T>
|
|
int mupdatedirect2VMT (Word* args, Word& result,
|
|
int message, Word& local, Supplier s) {
|
|
|
|
mupdatedirect2LocalInfo* li = (mupdatedirect2LocalInfo*) local.addr;
|
|
|
|
switch (message) {
|
|
|
|
|
|
case OPEN : {
|
|
if(li){
|
|
delete li;
|
|
local.addr=0;
|
|
}
|
|
|
|
T* oN = (T*) args[1].addr;
|
|
MemoryRelObject* rel = getMemRel(oN);
|
|
|
|
if(!rel) {return 0;}
|
|
|
|
int tidIndex = ((CcInt*) args[4].addr)->GetValue();
|
|
int noFuns = ((CcInt*) args[5].addr)->GetValue();
|
|
vector<int> funindexes;
|
|
Word elem;
|
|
for(int i=0;i<noFuns;i++){
|
|
Supplier s = qp->GetSupplier(args[6].addr, i);
|
|
qp->Request(s,elem);
|
|
int index = ((CcInt*) elem.addr)->GetValue();
|
|
funindexes.push_back(index);
|
|
}
|
|
|
|
local.addr = new mupdatedirect2LocalInfo(args[0], rel->getmmrel(),
|
|
tidIndex,
|
|
args[3], funindexes);
|
|
|
|
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 0;
|
|
|
|
}
|
|
|
|
|
|
ValueMapping mupdatedirect2VM[] = {
|
|
mupdatedirect2VMT<Mem>,
|
|
mupdatedirect2VMT<MPointer>
|
|
};
|
|
|
|
int mupdatedirect2Select(ListExpr args){
|
|
return Mem::checkType(nl->Second(args))?0:1;
|
|
}
|
|
|
|
/*
|
|
7.18.4 Description of operator ~mupdatedirect2~
|
|
|
|
*/
|
|
OperatorSpec mupdatedirect2Spec(
|
|
"stream(tuple(X) x mrel(tuple(Y) x IDENT x funlist -> stream(tuple(Y))",
|
|
"_ _ mupdatedirect2[_; funlist]",
|
|
"The first argument represents a stream of tuple containing a TID "
|
|
"attribute. "
|
|
"The second represents a main memory relation. "
|
|
"The third argument specifies the name of the tid attribute in the stream."
|
|
"The last argument is a list of named functions taking a tuple(X) and "
|
|
"a tuple(Y) producing an attribute according to the name's type "
|
|
" in the relation. The operator updates the tuples in the relation "
|
|
" with the tid coming from the tuple stream by replacing the attributes "
|
|
" in the funlist by the function results. The result is the incoming tuple "
|
|
" stream. Tuples having containing a tid that point to non existing tuples"
|
|
" in the relation are removed from the output stream.",
|
|
"query ten feed filter[.No > 3] addid mten "
|
|
"mupdatedirect2[TID; No : .No + ..No * 10] consume"
|
|
);
|
|
|
|
/*
|
|
|
|
7.18.5 Instance of operator ~mupdatebyid~
|
|
|
|
*/
|
|
Operator mupdatedirect2Op (
|
|
"mupdatedirect2",
|
|
mupdatedirect2Spec.getStr(),
|
|
2,
|
|
mupdatedirect2VM,
|
|
mupdatedirect2Select,
|
|
mupdatedirect2TM
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////// ORDERED RELATION ////
|
|
enum ChangeType{
|
|
MOInsert,
|
|
MODelete,
|
|
MOUpdate
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
7.19 Operator ~moinsert~
|
|
|
|
The Operator ~moinsert~ insert all tuples of an input stream into an
|
|
ordered main memory relation. The tuples of the input stream are given
|
|
an additional attribute of type 'tid' and added to the output stream.
|
|
|
|
*/
|
|
template<ChangeType ct>
|
|
class moinsertInfo {
|
|
public:
|
|
|
|
moinsertInfo(Word& w, ttree::TTree<TupleWrap,TupleComp>* _orel,
|
|
bool _flob, TupleType* _type,vector<int>* _attrPos)
|
|
: stream(w),orel(_orel),flob(_flob),type(_type),attrPos(_attrPos) {
|
|
stream.open();
|
|
}
|
|
|
|
~moinsertInfo() {
|
|
stream.close();
|
|
type->DeleteIfAllowed();
|
|
}
|
|
|
|
Tuple* next() {
|
|
Tuple* res = stream.request();
|
|
if(!res) { return 0; }
|
|
|
|
if((ct==MOInsert) && flob) {
|
|
res->bringToMemory();
|
|
}
|
|
|
|
// copy attributes of tuple from input stream
|
|
Tuple* newtup = new Tuple(type);
|
|
for(int i = 0; i < res->GetNoAttributes(); i++){
|
|
newtup->CopyAttribute(i,res,i);
|
|
}
|
|
|
|
TupleId tid = res->GetTupleId();
|
|
switch(ct){
|
|
case MOInsert : {
|
|
TupleWrap tw(res);
|
|
orel->insert(tw,attrPos);
|
|
}
|
|
break;
|
|
case MODelete : {
|
|
TupleWrap tw(res);
|
|
orel->remove(tw, attrPos);
|
|
}
|
|
break;
|
|
default : assert(false);
|
|
}
|
|
res->DeleteIfAllowed(); // remove old tuple
|
|
|
|
//get tuple id and append it to the stored tuple
|
|
Attribute* tidAttr = new TupleIdentifier(true,tid);
|
|
newtup->PutAttribute(newtup->GetNoAttributes()-1, tidAttr);
|
|
|
|
|
|
return newtup;
|
|
}
|
|
|
|
private:
|
|
Stream<Tuple> stream;
|
|
ttree::TTree<TupleWrap,TupleComp>* orel;
|
|
bool flob;
|
|
TupleType* type;
|
|
vector<int>* attrPos;
|
|
};
|
|
|
|
|
|
/*
|
|
|
|
7.19.2 Value Mapping Functions of operator ~moinsert~
|
|
|
|
*/
|
|
template<class T, ChangeType ct>
|
|
int moinsertValueMap (Word* args, Word& result,
|
|
int message, Word& local, Supplier s) {
|
|
|
|
moinsertInfo<ct>* li = (moinsertInfo<ct>*) local.addr;
|
|
|
|
switch (message) {
|
|
|
|
case OPEN : {
|
|
|
|
if(li) {
|
|
delete li;
|
|
local.addr=0;
|
|
}
|
|
|
|
qp->Open(args[0].addr);
|
|
|
|
T* oN = (T*) args[1].addr;
|
|
ListExpr ttype = nl->Second(qp->GetType(qp->GetSon(s,0)));
|
|
MemoryORelObject* orel = getMemORel(oN,ttype);
|
|
if(!orel) { return 0; }
|
|
|
|
TupleType* tt = new TupleType(nl->Second(GetTupleResultType(s)));
|
|
|
|
local.addr = new moinsertInfo<ct>(args[0],orel->getmmorel(),
|
|
orel->hasflob(),tt,
|
|
orel->getAttrPos());
|
|
|
|
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 0;
|
|
|
|
}
|
|
|
|
ValueMapping moinsertVM[] = {
|
|
moinsertValueMap<Mem,MOInsert>,
|
|
moinsertValueMap<MPointer,MOInsert>,
|
|
moinsertValueMap<Mem,MODelete>,
|
|
moinsertValueMap<MPointer,MODelete>
|
|
};
|
|
|
|
|
|
template<ChangeType ct>
|
|
int moinsertSelect(ListExpr args){
|
|
ListExpr t = nl->Second(args);
|
|
int n = -1;
|
|
if(Mem::checkType(t)) n = 0;
|
|
if(MPointer::checkType(t)) n = 1;
|
|
if(n<0) return -1;
|
|
if(ct == MOInsert)
|
|
return n;
|
|
if(ct == MODelete)
|
|
return n+2;
|
|
return -1;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
7.19.4 Description of operator ~moinsert~
|
|
|
|
*/
|
|
OperatorSpec moinsertSpec(
|
|
"stream(tuple(x)) x iMREL -> "
|
|
"stream(tuple(x@[TID:tid])), MREL in {string, mem, mpointer}",
|
|
"_ moinsert [_]",
|
|
"inserts the tuple of a stream into an "
|
|
"existing main memory ordered relation",
|
|
"query moinsert (ten feed head[5],moten) count"
|
|
);
|
|
|
|
/*
|
|
7.19.5 Instance of operator ~moinsert~
|
|
|
|
*/
|
|
Operator moinsertOp (
|
|
"moinsert",
|
|
moinsertSpec.getStr(),
|
|
4,
|
|
moinsertVM,
|
|
moinsertSelect<MOInsert>,
|
|
minsertTypeMap<2,true>
|
|
);
|
|
|
|
|
|
/*
|
|
7.20 Operator ~modelete~
|
|
|
|
The operator ~modelete~ deletes all tuple of the input stream from the given
|
|
main memory ordered relation. The tuples of the input stream including an
|
|
attribute of type 'tid' are appended to the output stream.
|
|
|
|
7.20.4 Description of operator ~modelete~
|
|
|
|
*/
|
|
OperatorSpec modeleteSpec(
|
|
"stream(tuple(x)) x MREL "
|
|
"-> stream(tuple(x@[TID:tid])), MREL in {string, mem, mpointer}",
|
|
"_ modelete [_]",
|
|
"all tuples of an input stream will be deleted from an "
|
|
"main memory ordered relation",
|
|
"query ten feed head[5] modelete['oten'] count"
|
|
);
|
|
|
|
/*
|
|
7.20.5 Instance of operator ~modelete~
|
|
|
|
*/
|
|
Operator modeleteOp (
|
|
"modelete",
|
|
modeleteSpec.getStr(),
|
|
4,
|
|
moinsertVM,
|
|
moinsertSelect<MODelete>,
|
|
minsertTypeMap<2,true>
|
|
);
|
|
|
|
|
|
/*
|
|
7.21 Operator ~moconsume~
|
|
|
|
The Operator ~moconsume~ creates an MemoryORelOBject for output on
|
|
an user interface, i.e. the console from
|
|
a input stream and the attribute identifiers over which the main
|
|
memory ordered relation will be sorted.
|
|
|
|
7.21.1 Type Mapping Functions of operator ~moconsume~
|
|
|
|
stream(tuple(x)) x (ident1 ... identn) -> mem(orel(tuple(tuple(x))))
|
|
|
|
*/
|
|
ListExpr moconsumeTypeMap(ListExpr args) {
|
|
|
|
if(nl->ListLength(args)!=2){
|
|
return listutils::typeError("(wrong number of arguments)");
|
|
}
|
|
if(!Stream<Tuple>::checkType(nl->First(args))) {
|
|
return listutils::typeError ("stream(tuple) expected!");
|
|
}
|
|
ListExpr tupleDescr = nl->Second(nl->First(args));
|
|
ListExpr attrList = nl->Second(tupleDescr);
|
|
ListExpr keyList = nl->Second(args);
|
|
if(nl->AtomType(keyList)!=NoAtom){
|
|
return listutils::typeError("expected list of attribute names "
|
|
"as the second argument");
|
|
}
|
|
if(nl->IsEmpty(keyList)){
|
|
return listutils::typeError("keylist must not be empty");
|
|
}
|
|
ListExpr appendList = nl->TheEmptyList();
|
|
ListExpr last = nl->TheEmptyList();
|
|
bool first = true;
|
|
while(!nl->IsEmpty(keyList)){
|
|
ListExpr currentKey = nl->First(keyList);
|
|
keyList = nl->Rest(keyList);
|
|
if(nl->AtomType(currentKey) != SymbolType){
|
|
return listutils::typeError("found invalid attribute name in"
|
|
" key list");
|
|
}
|
|
string name = nl->SymbolValue(currentKey);
|
|
ListExpr attrType;
|
|
int index = listutils::findAttribute(attrList, name, attrType);
|
|
if(!index){
|
|
return listutils::typeError(name + " is not a member of the tuple");
|
|
}
|
|
if(first){
|
|
appendList = nl->OneElemList(nl->IntAtom(index));
|
|
last = appendList;
|
|
first = false;
|
|
} else {
|
|
last = nl->Append(last, nl->IntAtom(index));
|
|
}
|
|
}
|
|
|
|
|
|
ListExpr orel = nl->ThreeElemList(
|
|
listutils::basicSymbol<OrderedRelation>(),
|
|
tupleDescr,
|
|
nl->Second(args));
|
|
|
|
ListExpr resType = MPointer::wrapType(Mem::wrapType(orel));
|
|
return nl->ThreeElemList( nl->SymbolAtom(Symbols::APPEND()),
|
|
appendList,
|
|
resType);
|
|
}
|
|
|
|
|
|
/*
|
|
7.21.2 Value Mapping Function of operator ~moconsume~
|
|
|
|
*/
|
|
template<bool flob>
|
|
int moconsumeVM (Word* args, Word& result,
|
|
int message, Word& local, Supplier s) {
|
|
|
|
|
|
vector<int>* pos = new vector<int>();
|
|
for(int i=2;i<qp->GetNoSons(s);i++){
|
|
pos->push_back( ((CcInt*) args[i].addr)->GetValue());
|
|
}
|
|
ttree::TTree<TupleWrap,TupleComp>* tree;
|
|
tree = new ttree::TTree<TupleWrap,TupleComp>(16,18);
|
|
ListExpr objectType = nl->Second(qp->GetType(s));
|
|
|
|
MemoryORelObject* mor = new MemoryORelObject(tree,pos,0,
|
|
nl->ToString(objectType), flob,
|
|
getDBname());
|
|
|
|
Stream<Tuple> stream(args[0]);
|
|
stream.open();
|
|
Tuple* tup = 0;
|
|
bool ok = true;
|
|
while( ((tup = stream.request()) != 0) && ok) {
|
|
ok = mor->addTuple(tup);
|
|
tup->DeleteIfAllowed();
|
|
}
|
|
stream.close();
|
|
result = qp->ResultStorage(s);
|
|
MPointer* res = (MPointer*) result.addr;
|
|
res->setPointer(mor);
|
|
mor->deleteIfAllowed();
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
7.21.4 Description of operator ~moconsume~
|
|
|
|
*/
|
|
OperatorSpec moconsumeSpec(
|
|
"stream(Tuple) x (ident1 ... identn) "
|
|
"->(mpointer (mem(orel (tuple(x)) (ident1 ... identn))))",
|
|
"_ moconsume[list]",
|
|
"collects the objects from a stream(tuple) into a memory ordered relation",
|
|
"query mten mfeed head[2] moconsume[No]"
|
|
);
|
|
|
|
|
|
/*
|
|
7.21.5 Instance of operator ~moconsume~
|
|
|
|
*/
|
|
Operator moconsumeOp (
|
|
"moconsume",
|
|
moconsumeSpec.getStr(),
|
|
moconsumeVM<false>,
|
|
Operator::SimpleSelect,
|
|
moconsumeTypeMap
|
|
);
|
|
|
|
|
|
/*
|
|
7.21.4 Description of operator ~moconsumeflob~
|
|
|
|
*/
|
|
OperatorSpec moconsumeflobSpec(
|
|
"stream(Tuple) x (ident1 ... identn) "
|
|
"->(mpointer (mem(orel (tuple(x)) (ident1 ... identn))))",
|
|
"_ moconsumeflob[list]",
|
|
"collects the objects from a stream(tuple) into a memory ordered relation",
|
|
"query mten mfeed head[2] moconsumeflob[No]"
|
|
);
|
|
|
|
|
|
/*
|
|
7.21.5 Instance of operator ~moconsumeflob~
|
|
|
|
*/
|
|
Operator moconsumeflobOp (
|
|
"moconsumeflob",
|
|
moconsumeflobSpec.getStr(),
|
|
moconsumeVM<true>,
|
|
Operator::SimpleSelect,
|
|
moconsumeTypeMap
|
|
);
|
|
|
|
|
|
/*
|
|
7.24 Operators ~morange~, ~moleftrange~, ~morightrange~
|
|
In case of ~morange~ finds all tuples in the given MemoryORelObject
|
|
(as first argument) which are between the first and the second
|
|
attribute value (as second and third argument).
|
|
In case of ~moleftrange~, ~morightrange~ finds all tuples in
|
|
the given MemoryORelObject (as first argument) which are left or
|
|
right of the given value (as second argument).
|
|
|
|
7.24.1 General Type Mapping Functions of operators ~morange~, ~moleftrange~
|
|
and ~morightrange~
|
|
|
|
{string, mem(orel(tuple(x)))} x T x T -> stream(tuple(x)) or
|
|
|
|
{string, mem(orel(tuple(x)))} x T -> stream(tuple(x))
|
|
|
|
*/
|
|
enum RangeKind {
|
|
LeftRange,
|
|
RightRange,
|
|
Range
|
|
};
|
|
|
|
template<RangeKind rk>
|
|
ListExpr morangeTypeMap(ListExpr args) {
|
|
// if morange
|
|
if(rk==Range && nl->ListLength(args)!=3){
|
|
return listutils::typeError("three arguments expected");
|
|
}
|
|
// if moleftrange or morightrange
|
|
if((rk==LeftRange || rk==RightRange) && nl->ListLength(args)!=2){
|
|
return listutils::typeError("two arguments expected");
|
|
}
|
|
|
|
ListExpr a1 = nl->First(args); //mem(orel)
|
|
ListExpr a2 = nl->Second(args);
|
|
// if morange
|
|
ListExpr a3 = nl->TheEmptyList();
|
|
|
|
string err;
|
|
if(rk==Range) {
|
|
err = "{mpointer, mem(orel)} x T x T expected";
|
|
} else {
|
|
err = "{mpointer, mem(orel)} x T expected";
|
|
}
|
|
|
|
string errMsg;
|
|
if(!getMemSubType(nl->First(args), a1)){
|
|
return listutils::typeError("first argument is not a memory object");
|
|
}
|
|
|
|
// process MemoryORelObject
|
|
if(!listutils::isOrelDescription(a1)) {
|
|
return listutils::typeError(err + " (first arg is not an orel)");
|
|
}
|
|
|
|
// extract type of key2 if morange
|
|
if(rk==Range) {
|
|
a3 = nl->Third(args);
|
|
} else {
|
|
a3 = a2;
|
|
}
|
|
if(!nl->Equal(a2,a3)){
|
|
return listutils::typeError("third argument and second argument "
|
|
"have different types");
|
|
}
|
|
|
|
|
|
ListExpr attrList = nl->Second(nl->Second(a1));
|
|
ListExpr attrNames = nl->Third(a1);
|
|
ListExpr typeList = nl->TheEmptyList();
|
|
ListExpr lastType = nl->TheEmptyList();
|
|
ListExpr indexList = nl->TheEmptyList();
|
|
ListExpr lastIndex = nl->TheEmptyList();
|
|
bool first = true;
|
|
|
|
// extract the types from the key attributes and collect their positions
|
|
while(!nl->IsEmpty(attrNames)){
|
|
ListExpr attrName = nl->First(attrNames);
|
|
attrNames = nl->Rest(attrNames);
|
|
if(nl->AtomType(attrName)!=SymbolType){
|
|
return listutils::typeError("error in orel description");
|
|
}
|
|
string name = nl->SymbolValue(attrName);
|
|
ListExpr type;
|
|
int index = listutils::findAttribute(attrList, name, type);
|
|
if(!index){
|
|
return listutils::typeError("invalid orel description");
|
|
}
|
|
if(first){
|
|
typeList = nl->OneElemList(type);
|
|
lastType = typeList;
|
|
indexList = nl->OneElemList( nl->IntAtom(index-1));
|
|
lastIndex = indexList;
|
|
first = false;
|
|
} else {
|
|
lastType = nl->Append(lastType, type);
|
|
lastIndex = nl->Append(lastIndex, nl->IntAtom(index-1));
|
|
}
|
|
}
|
|
|
|
if(!nl->Equal(typeList, a2)){
|
|
return listutils::typeError("key attribute type of orel does not fit "
|
|
"the boundary attributes");
|
|
}
|
|
if(!nl->Equal(typeList, a3)){
|
|
return listutils::typeError("key attribute type of orel does not fit "
|
|
"the max boundary attributes (1)");
|
|
}
|
|
|
|
ListExpr resType = nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()),
|
|
nl->Second(a1));
|
|
return nl->ThreeElemList(nl->SymbolAtom(Symbols::APPEND()),
|
|
indexList,
|
|
resType);
|
|
}
|
|
|
|
class morangeInfo{
|
|
public:
|
|
|
|
morangeInfo(ttree::TTree<TupleWrap,TupleComp>* _tree,
|
|
TupleWrap _min,
|
|
TupleWrap _max,
|
|
vector<int> _attrPos)
|
|
: tree(_tree),max(_max),attrPos(_attrPos) {
|
|
|
|
if(_min()==0){ // no left boundary, start from beginning
|
|
iter = tree->begin();
|
|
} else {
|
|
iter = tree->tail(_min, &attrPos);
|
|
}
|
|
}
|
|
|
|
~morangeInfo(){}
|
|
|
|
|
|
Tuple* next() {
|
|
if(iter.end()){ // scan finished
|
|
return 0;
|
|
}
|
|
Tuple* result = (*iter).getPointer();
|
|
if(!result){
|
|
return 0;
|
|
}
|
|
if(max()==0){ // no right boundary
|
|
result->IncReference();
|
|
iter++;
|
|
return result;
|
|
}
|
|
// check right boundary
|
|
if(TupleComp::smaller(max(), result, &attrPos)){
|
|
return 0;
|
|
}
|
|
result->IncReference();
|
|
iter++;
|
|
return result;
|
|
}
|
|
|
|
private:
|
|
ttree::TTree<TupleWrap,TupleComp>* tree;
|
|
TupleWrap max;
|
|
vector<int> attrPos;
|
|
ttree::Iterator<TupleWrap,TupleComp> iter;
|
|
};
|
|
|
|
/*
|
|
7.24.2 The Value Mapping Function of operator ~mrange~, ~moleftrange~ and
|
|
~morightrange~
|
|
|
|
*/
|
|
template<class T, RangeKind rk>
|
|
int morangeVMT (Word* args, Word& result,
|
|
int message, Word& local, Supplier s) {
|
|
|
|
|
|
morangeInfo* li = (morangeInfo*) local.addr;
|
|
|
|
switch (message) {
|
|
|
|
case OPEN: {
|
|
|
|
if(li){
|
|
delete li;
|
|
local.addr=0;
|
|
}
|
|
|
|
T* orelN = (T*) args[0].addr;
|
|
MemoryORelObject* orel =
|
|
getMemORel(orelN, nl->Second(qp->GetType(s)));
|
|
if(!orel){
|
|
return 0;
|
|
}
|
|
Tuple* minTuple = 0;
|
|
Tuple* maxTuple = 0;
|
|
vector<int> positions;
|
|
// collect minTuple, maxTuple and
|
|
// positions
|
|
TupleType* tt = new TupleType(nl->Second(GetTupleResultType(s)));
|
|
int keyPos = rk==Range?3:2;
|
|
for(int i=keyPos;i<qp->GetNoSons(s); i++){
|
|
positions.push_back(((CcInt*)args[i].addr)->GetValue());
|
|
}
|
|
// collect minTuple
|
|
int maxpos = 1;
|
|
if(rk!=LeftRange){ // minValue is required for rightrange and range
|
|
maxpos = 2;
|
|
minTuple = new Tuple(tt);
|
|
Word aw;
|
|
for(size_t i=0;i<positions.size();i++){
|
|
Supplier son = qp->GetSupplier(args[1].addr,i);
|
|
qp->Request(son,aw);
|
|
Attribute* attr = (Attribute*) aw.addr;
|
|
minTuple->PutAttribute(positions[i], attr->Copy());
|
|
}
|
|
}
|
|
|
|
// collect maxTuple
|
|
if(rk!=RightRange){ // maxValue is required for leftrange and range
|
|
maxTuple = new Tuple(tt);
|
|
Word aw;
|
|
for(size_t i=0;i<positions.size();i++){
|
|
Supplier son = qp->GetSupplier(args[maxpos].addr,i);
|
|
qp->Request(son,aw);
|
|
Attribute* attr = (Attribute*) aw.addr;
|
|
maxTuple->PutAttribute(positions[i], attr->Copy());
|
|
}
|
|
}
|
|
// the tuple comparator vector starts counting with 1
|
|
for(size_t i=0;i<positions.size();i++){
|
|
positions[i]++;
|
|
}
|
|
|
|
local.addr = new morangeInfo(orel->getmmorel(),
|
|
minTuple,maxTuple,
|
|
positions);
|
|
if(minTuple){
|
|
minTuple->DeleteIfAllowed();
|
|
}
|
|
if(maxTuple){
|
|
maxTuple->DeleteIfAllowed();
|
|
}
|
|
tt->DeleteIfAllowed();
|
|
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;
|
|
}
|
|
|
|
|
|
ValueMapping morangeVM[] = {
|
|
morangeVMT<Mem,Range>,
|
|
morangeVMT<MPointer,Range>,
|
|
|
|
morangeVMT<Mem,LeftRange>,
|
|
morangeVMT<MPointer,LeftRange>,
|
|
|
|
morangeVMT<Mem,RightRange>,
|
|
morangeVMT<MPointer,RightRange>
|
|
};
|
|
|
|
template<RangeKind rk>
|
|
int morangeSelect(ListExpr args){
|
|
int n = Mem::checkType(nl->First(args))?0:1;
|
|
if(n<0) return -1;
|
|
switch(rk){
|
|
case Range : return n;
|
|
case LeftRange : return n + 2;
|
|
case RightRange : return n + 4;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
/*
|
|
7.24.4 Description of operator ~morange~
|
|
|
|
*/
|
|
OperatorSpec morangeSpec(
|
|
"MOREL x T x T -> stream(tuple(x)), MOREL in{mem, mpointer}",
|
|
"_ morange [_,_]",
|
|
"returns all tuples in a main memory ordered relation whose attributes "
|
|
"are lying between the two given values",
|
|
"query 'oten' morange[2,2] count"
|
|
);
|
|
|
|
|
|
/*
|
|
7.25.4 Description of operator ~moleftrange~
|
|
|
|
*/
|
|
OperatorSpec moleftrangeSpec(
|
|
"MOREL x T -> stream(tuple(x)), MOREL in {mem, mpointer}",
|
|
"_ moleftrange [_]",
|
|
"returns all tuples in a main memory ordered relation whose attributes "
|
|
"are smaller than the given value",
|
|
"query 'oten' moleftrange[2] count"
|
|
);
|
|
|
|
/*
|
|
7.26.4 Description of operator ~morightrange~
|
|
|
|
*/
|
|
OperatorSpec morightrangeSpec(
|
|
"MOREL x T -> stream(tuple(x)), MOREL in {mem, mpointer}",
|
|
"_ morightrange [_]",
|
|
"returns all tuples in a main memory ordered relation whose attributes "
|
|
"are larger than the given value",
|
|
"query 'oten' morightrange[8] count"
|
|
);
|
|
|
|
|
|
|
|
/*
|
|
7.24.5 Instance of operator ~morange~
|
|
|
|
*/
|
|
Operator morangeOp (
|
|
"morange",
|
|
morangeSpec.getStr(),
|
|
6,
|
|
morangeVM,
|
|
morangeSelect<Range>,
|
|
morangeTypeMap<Range>
|
|
);
|
|
|
|
/*
|
|
7.25.5 Instance of operator ~moleftrange~
|
|
|
|
*/
|
|
Operator moleftrangeOp (
|
|
"moleftrange",
|
|
moleftrangeSpec.getStr(),
|
|
6,
|
|
morangeVM,
|
|
morangeSelect<LeftRange>,
|
|
morangeTypeMap<LeftRange>
|
|
);
|
|
|
|
/*
|
|
7.26.5 Instance of operator ~morightrange~
|
|
|
|
*/
|
|
Operator morightrangeOp (
|
|
"morightrange",
|
|
morightrangeSpec.getStr(),
|
|
6,
|
|
morangeVM,
|
|
morangeSelect<RightRange>,
|
|
morangeTypeMap<RightRange>
|
|
);
|
|
|
|
|
|
enum SPType{
|
|
DIJKSTRA,
|
|
ASTAR
|
|
};
|
|
|
|
Tuple* findTuple(ttree::TTree<TupleWrap,TupleComp>* mmorel,
|
|
int nr, int prev) {
|
|
|
|
CcInt* startNodeInt = new CcInt(true,prev);
|
|
CcInt* endNodeInt = new CcInt(true,nr);
|
|
|
|
ttree::Iterator<TupleWrap,TupleComp> it = mmorel->begin();
|
|
|
|
Tuple* tup=0;
|
|
while(!it.end()) {
|
|
tup = (*it).getPointer();
|
|
if(!tup)
|
|
return 0;
|
|
// find all tuples with startnode as first argument
|
|
if(tup->GetAttribute(0)->Compare(startNodeInt) < 0)
|
|
it++;
|
|
// find EndNode in second argument
|
|
else if(tup->GetAttribute(1)->Compare(endNodeInt) < 0)
|
|
it++;
|
|
else break;
|
|
}
|
|
|
|
startNodeInt->DeleteIfAllowed();
|
|
endNodeInt->DeleteIfAllowed();
|
|
return tup;
|
|
}
|
|
|
|
|
|
bool appendTuple(Tuple* tup,TupleType* tt,
|
|
int seqNo,
|
|
ttree::TTree<TupleWrap,TupleComp>* result) {
|
|
Tuple* newTuple = new Tuple(tt);
|
|
int i = 0;
|
|
for(; i<tup->GetNoAttributes(); i++) {
|
|
newTuple->CopyAttribute(i,tup,i);
|
|
}
|
|
int s = seqNo;
|
|
CcInt* noOfNodes = new CcInt(true, s);
|
|
newTuple->PutAttribute(i,noOfNodes);
|
|
TupleWrap tw(newTuple);
|
|
result->insert(tw,i+1); // sort by SeqNo
|
|
newTuple->DeleteIfAllowed();
|
|
return true;
|
|
}
|
|
|
|
QueueEntryWrap findNextNode(
|
|
ttree::TTree<QueueEntryWrap,EntryComp>* visitedNodes,
|
|
QueueEntryWrap& current) {
|
|
|
|
ttree::Iterator<QueueEntryWrap,EntryComp> iter = visitedNodes->begin();
|
|
while(!iter.end()) {
|
|
QueueEntryWrap entry = *iter;
|
|
|
|
if(entry.getPointer()->nodeNumber == current()->prev) {
|
|
return entry;
|
|
}
|
|
iter++;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
|
|
7.27 Operator ~moshortestpathd~ and ~moshortestpatha~
|
|
|
|
The Operator ~moshortestpathd~ and ~moshortestpatha~ calculate the shortest
|
|
path between two given nodes of a graph. The graph is in this case represented
|
|
by a main memory ordered relation. The tuples of such a relation need to
|
|
have two integer values as their first two attributes identifying the start and
|
|
end node of an edge and at least one double value containing the cost
|
|
the edge.
|
|
The main memory relation must be ordered first by the start nodes of the tuples
|
|
then by the end nodes.
|
|
The operator expects an main memory ordered relation, two integers describing
|
|
the start and goal node of the path, an integer choosing the resulting output
|
|
of the shortest path calculation, as well as an cost function, which maps
|
|
the values of the tuples to a double value. The Operator ~moshortestpatha~
|
|
expects an additional function calculating the distance to the goal node.
|
|
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.
|
|
For all cases an additional attribute 'seqNo' of type integer will be appended
|
|
to the tuples of the output stream.
|
|
The Operator ~moshortestpathd~ uses Dijkstras Algorithm and the Operator
|
|
~moshortestpatha~ uses the AStar-Algorithm.
|
|
|
|
7.27.1 General Type Mapping for Operators ~moshortestpathd~ and
|
|
~moshortestpatha~
|
|
|
|
{string, mem(orel(tuple(X)))} x int x int x int x (tuple->real)
|
|
-> stream(tuple(a1:t1,...an+1:tn+1)) and
|
|
|
|
{string, mem(orel(tuple(X)))} x int x int x int x (tuple->real)
|
|
x (tuple->real) ->
|
|
stream(tuple(a1:t1,...an+1:tn+1))
|
|
|
|
*/
|
|
template<SPType sptype>
|
|
ListExpr moshortestpathTypeMap(ListExpr args) {
|
|
|
|
if(sptype == DIJKSTRA && nl->ListLength(args) != 5) {
|
|
return listutils::typeError("moshortestpath expects 5 arguments");
|
|
}
|
|
|
|
if(sptype == ASTAR && nl->ListLength(args) != 6) {
|
|
return listutils::typeError("moshortestpath expects 6 arguments");
|
|
}
|
|
|
|
// process first arg
|
|
ListExpr a1;
|
|
if(!getMemSubType(nl->First(args),a1)){
|
|
return listutils::typeError("first arg is not a memory object");
|
|
}
|
|
|
|
//MemoryORelObject
|
|
if(!listutils::isOrelDescription(a1)) {
|
|
return listutils::typeError("first arg is not an orel");
|
|
}
|
|
|
|
ListExpr startNodeList = nl->Second(args);
|
|
ListExpr endNodeList = nl->Third(args);
|
|
ListExpr resultSelect = nl->Fourth(args);
|
|
ListExpr functionWeightMap = nl->Fifth(args);
|
|
ListExpr functionDistMap;
|
|
if(sptype == ASTAR){
|
|
functionDistMap = nl->Sixth(args);
|
|
}
|
|
|
|
ListExpr orelTuple = nl->Second(a1);
|
|
|
|
ListExpr orelAttrList(nl->Second(orelTuple));
|
|
|
|
if(!nl->HasMinLength(orelAttrList, 3)){
|
|
return listutils::typeError("Ordered relation must have at "
|
|
"least 3 attributes");
|
|
}
|
|
|
|
|
|
ListExpr firstAttr = nl->First(orelAttrList);
|
|
if(!CcInt::checkType(nl->Second(firstAttr))){
|
|
return listutils::typeError("first attribute must be of type int");
|
|
}
|
|
ListExpr secondAttr = nl->Second(orelAttrList);
|
|
if(!CcInt::checkType(nl->Second(secondAttr))){
|
|
return listutils::typeError("second attribute must be of type int");
|
|
}
|
|
|
|
//Check of second argument
|
|
if (!CcInt::checkType(startNodeList)) {
|
|
return listutils::typeError("Second argument must be int");
|
|
}
|
|
|
|
//Check of third argument
|
|
if (!CcInt::checkType(endNodeList)) {
|
|
return listutils::typeError("Third argument should be int");
|
|
}
|
|
|
|
//Check of fourth argument
|
|
if(!CcInt::checkType(resultSelect) ) {
|
|
return listutils::typeError("Fourth argument should be int");
|
|
}
|
|
|
|
//Check of fifth argument
|
|
if(!listutils::isMap<1>(functionWeightMap)) {
|
|
return listutils::typeError("Fifth argument should be a map");
|
|
}
|
|
|
|
ListExpr mapTuple = nl->Second(functionWeightMap);
|
|
|
|
if(!nl->Equal(orelTuple,mapTuple)) {
|
|
return listutils::typeError("Tuple of map function must match orel tuple");
|
|
}
|
|
|
|
ListExpr mapres = nl->Third(functionWeightMap);
|
|
|
|
if(!CcReal::checkType(mapres)) {
|
|
return listutils::typeError(
|
|
"Wrong mapping result type for oshortestpathd");
|
|
}
|
|
|
|
// check of sixth argument if ASTAR
|
|
if(sptype == ASTAR) {
|
|
if (!listutils::isMap<1>(functionDistMap)) {
|
|
return listutils::typeError(
|
|
"Sixth argument must be a map");
|
|
}
|
|
ListExpr mapTuple2 = nl->Second(functionDistMap);
|
|
|
|
if (!nl->Equal(orelTuple,mapTuple2)) {
|
|
return listutils::typeError(
|
|
"Tuple of map function must match orel tuple");
|
|
}
|
|
ListExpr mapres2 = nl->Third(functionDistMap);
|
|
|
|
if(!CcReal::checkType(mapres2)) {
|
|
return listutils::typeError(
|
|
"Wrong mapping result type for oshortestpath");
|
|
}
|
|
}
|
|
|
|
// appends Attribute SeqNo to Attributes 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;
|
|
}
|
|
|
|
|
|
class moshortestpathdInfo {
|
|
public:
|
|
|
|
moshortestpathdInfo(ttree::TTree<TupleWrap,TupleComp>* _tree,
|
|
int _startNode, int _endNode, int _resultSelect,
|
|
Word& _arg, TupleType* _tt)
|
|
: mmorel(_tree),startNode(_startNode),
|
|
endNode(_endNode),resultSelect(_resultSelect),
|
|
arg(_arg),tt(_tt),seqNo(1) {
|
|
|
|
queue = new Queue();
|
|
visitedNodes = new ttree::TTree<QueueEntryWrap,EntryComp>(16,18);
|
|
sptree = new ttree::TTree<TupleWrap,TupleComp>(16,18);
|
|
result = new ttree::TTree<TupleWrap,TupleComp>(16,18);
|
|
|
|
bool found = shortestPath();
|
|
if(resultSelect<0 || resultSelect>3){ // bring to allowed values
|
|
resultSelect = 0;
|
|
}
|
|
if(found || resultSelect == 3) {
|
|
resultSelection();
|
|
} else {
|
|
cerr << "no path found" << endl;
|
|
}
|
|
iterator = result->begin();
|
|
}
|
|
|
|
~moshortestpathdInfo() {
|
|
while(!queue->empty())
|
|
queue->pop();
|
|
delete queue;
|
|
|
|
tt->DeleteIfAllowed();
|
|
tt = 0;
|
|
|
|
delete visitedNodes;
|
|
delete result;
|
|
delete sptree;
|
|
};
|
|
|
|
Tuple* next() {
|
|
if(iterator.end())
|
|
return 0;
|
|
Tuple* res = (*iterator).getPointer();
|
|
if(res==NULL) {
|
|
return 0;
|
|
}
|
|
iterator++;
|
|
res->IncReference();
|
|
return res;
|
|
}
|
|
|
|
private:
|
|
Word funResult;
|
|
|
|
|
|
/*
|
|
~shortestpath~
|
|
|
|
*/
|
|
bool shortestPath() {
|
|
|
|
// INIT
|
|
int toNode = startNode;
|
|
|
|
QueueEntry* startEntry = new QueueEntry(startNode,-1,0.0,0.0);
|
|
QueueEntryWrap qw(startEntry);
|
|
startEntry->DeleteIfAllowed();
|
|
queue->push(qw);
|
|
visitedNodes->insert(qw);
|
|
|
|
double dist = 0.0;
|
|
|
|
// SEARCH SHORTESTPATH
|
|
while(!queue->empty()) {
|
|
current = queue->top();
|
|
current()->visited = true;
|
|
queue->pop();
|
|
|
|
// goal node found
|
|
if (resultSelect<3 && current()->nodeNumber == endNode) {
|
|
return true;
|
|
}
|
|
// process next node
|
|
else {
|
|
CcInt* currentNodeNumber = new CcInt(true,current()->nodeNumber);
|
|
// get tuple with currentNodeNumber as startnode
|
|
ttree::Iterator<TupleWrap,TupleComp> it = mmorel->begin();
|
|
while(!it.end()) {
|
|
Tuple* tup = (*it).getPointer();
|
|
if(tup->GetAttribute(0)->Compare(currentNodeNumber) < 0) {
|
|
it++;
|
|
}
|
|
// tuple found
|
|
else break;
|
|
}
|
|
// process edges
|
|
while(!it.end()) {
|
|
|
|
Tuple* currentTuple = (*it).getPointer();
|
|
// all edges processed
|
|
if(currentTuple->GetAttribute(0)->Compare(currentNodeNumber) > 0) {
|
|
break;
|
|
}
|
|
if(resultSelect!=3) {
|
|
TupleWrap tw(currentTuple);
|
|
sptree->insert(tw);
|
|
}
|
|
toNode = ((CcInt*)currentTuple->GetAttribute(1))->GetIntval();
|
|
|
|
if(current()->nodeNumber != toNode) {
|
|
ArgVectorPointer funArgs = qp->Argument(arg.addr);
|
|
funResult.addr = 0;
|
|
((*funArgs)[0]).setAddr(currentTuple);
|
|
qp->Request(arg.addr,funResult);
|
|
double edgeCost = ((CcReal*)funResult.addr)->GetRealval();
|
|
if (edgeCost < 0.0) {
|
|
cerr << "Found negativ edge cost computation aborted." << endl;
|
|
return 0;
|
|
}
|
|
dist = current()->dist + edgeCost;
|
|
bool contained = false;
|
|
ttree::Iterator<QueueEntryWrap,EntryComp> it =
|
|
visitedNodes->begin();
|
|
|
|
// check if shortening of path possible
|
|
while(!it.end()) {
|
|
QueueEntryWrap entry = *it;
|
|
if(entry.getPointer()->nodeNumber == toNode) {
|
|
if(entry.getPointer()->dist > dist) {
|
|
QueueEntry* prevEntry = new QueueEntry(entry()->nodeNumber,
|
|
entry()->prev,
|
|
entry()->dist,
|
|
entry()->priority);
|
|
prevEntry->visited = entry()->visited;
|
|
entry()->dist = dist;
|
|
entry()->prev = current()->nodeNumber;
|
|
entry()->priority = dist;
|
|
if(entry()->visited){
|
|
QueueEntryWrap qw(prevEntry);
|
|
visitedNodes->update(entry,qw);
|
|
}
|
|
prevEntry->DeleteIfAllowed();
|
|
}
|
|
contained = true;
|
|
break;
|
|
}
|
|
it++;
|
|
}
|
|
|
|
if(!contained) {
|
|
QueueEntry* to =
|
|
new QueueEntry(toNode,current()->nodeNumber,dist,dist);
|
|
QueueEntryWrap qw(to);
|
|
to->DeleteIfAllowed();
|
|
visitedNodes->insert(qw,true);
|
|
queue->push(qw);
|
|
if(resultSelect==3){
|
|
TupleWrap tw(currentTuple);
|
|
sptree->insert(tw);
|
|
}
|
|
currentTuple->IncReference();
|
|
}
|
|
}
|
|
it++;
|
|
}
|
|
currentNodeNumber->DeleteIfAllowed();
|
|
}
|
|
} // end while search shortestpath
|
|
return false;
|
|
}
|
|
|
|
|
|
void resultSelection() {
|
|
switch(resultSelect) {
|
|
case 0: { // shortest path
|
|
|
|
Tuple* currentTuple =
|
|
findTuple(mmorel,current()->nodeNumber,current()->prev);
|
|
bool found = false;
|
|
|
|
while (!found && currentTuple != 0) {
|
|
|
|
appendTuple(currentTuple,tt,seqNo,result);
|
|
seqNo++;
|
|
|
|
if(current()->prev != startNode) {
|
|
current = findNextNode(visitedNodes,current);
|
|
|
|
currentTuple =
|
|
findTuple(mmorel,current()->nodeNumber,current()->prev);
|
|
}
|
|
else {
|
|
found = true;
|
|
if(currentTuple != 0) {
|
|
currentTuple->DeleteIfAllowed();
|
|
currentTuple = 0;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 1: { //Remaining elements in priority queue
|
|
while(queue->size() > 0) {
|
|
current = queue->top();
|
|
queue->pop();
|
|
Tuple* currentTuple = findTuple(mmorel,
|
|
current()->nodeNumber,
|
|
current()->prev);
|
|
appendTuple(currentTuple,tt,seqNo,result);
|
|
seqNo++;
|
|
}
|
|
break;
|
|
}
|
|
case 2: { //visited sections
|
|
ttree::Iterator<TupleWrap,TupleComp> iter = sptree->begin();
|
|
while(!iter.end()) {
|
|
Tuple* currentTuple = (*iter).getPointer();
|
|
appendTuple(currentTuple,tt,seqNo,result);
|
|
iter++;
|
|
seqNo++;
|
|
}
|
|
break;
|
|
}
|
|
case 3: { //shortest path tree
|
|
ttree::Iterator<TupleWrap,TupleComp> iter = sptree->begin();
|
|
while(!iter.end()) {
|
|
Tuple* currentTuple = (*iter).getPointer();
|
|
appendTuple(currentTuple,tt,seqNo,result);
|
|
iter++;
|
|
seqNo++;
|
|
}
|
|
break;
|
|
}
|
|
|
|
default: { //should have never been reached
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
protected:
|
|
|
|
ttree::TTree<TupleWrap,TupleComp>* mmorel;
|
|
ttree::Iterator<TupleWrap,TupleComp> iterator;
|
|
int startNode;
|
|
int endNode;
|
|
int resultSelect;
|
|
Word arg;
|
|
TupleType* tt;
|
|
int seqNo;
|
|
Queue* queue;
|
|
|
|
ttree::TTree<QueueEntryWrap,EntryComp>* visitedNodes;
|
|
ttree::TTree<TupleWrap,TupleComp>* sptree;
|
|
ttree::TTree<TupleWrap,TupleComp>* result;
|
|
|
|
|
|
QueueEntryWrap current;
|
|
int seqNoAttrIndex;
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
7.27.2 Value Mapping Function of operator ~moshortestpathd~
|
|
|
|
*/
|
|
template<class T>
|
|
int moshortestpathdValueMap(Word* args, Word& result, int message,
|
|
Word& local, Supplier s) {
|
|
|
|
moshortestpathdInfo* li = (moshortestpathdInfo*) local.addr;
|
|
|
|
switch(message) {
|
|
|
|
case OPEN: {
|
|
|
|
if(li) {
|
|
delete li;
|
|
local.addr=0;
|
|
}
|
|
|
|
int resultSelect = ((CcInt*)args[3].addr)->GetIntval();
|
|
if(resultSelect<0 || resultSelect>3) {
|
|
cerr << "Selected result value does not exist. Enter 0 for shortest "
|
|
<< "path, 1 for remaining priority queue elements, 2 for visited "
|
|
<< "edges, 3 for shortest path tree." << endl;
|
|
return 0;
|
|
}
|
|
|
|
// Check for simplest Case
|
|
int startNode = ((CcInt*)args[1].addr)->GetIntval();
|
|
int endNode = ((CcInt*)args[2].addr)->GetIntval();
|
|
if(resultSelect<3) {
|
|
if(startNode == endNode) {
|
|
cerr << "source and target node are equal, no path";
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
ListExpr tupleType = GetTupleResultType(s);
|
|
TupleType* tt = new TupleType(nl->Second(tupleType));
|
|
|
|
T* orelN = (T*) args[0].addr;
|
|
MemoryORelObject* orel = getMemORel(orelN, nl->Second(qp->GetType(s)));
|
|
if(!orel){
|
|
return 0;
|
|
}
|
|
|
|
local.addr = new moshortestpathdInfo(orel->getmmorel(),
|
|
startNode,
|
|
endNode,
|
|
resultSelect,
|
|
args[4], 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 0;
|
|
}
|
|
|
|
|
|
ValueMapping moshortestpathdVM[] = {
|
|
moshortestpathdValueMap<Mem>,
|
|
moshortestpathdValueMap<MPointer>
|
|
};
|
|
|
|
|
|
int moshortestpathSelect(ListExpr args){
|
|
return Mem::checkType(nl->First(args))?0:1;
|
|
}
|
|
|
|
|
|
/*
|
|
7.27.4 Specification of operator ~moshortestpathd~
|
|
|
|
*/
|
|
OperatorSpec moshortestpathdSpec(
|
|
"MOREL x int x int x int x "
|
|
"(tuple->real) -> stream(tuple(a1:t1,...an+1:tn+1)), "
|
|
"MOREL in {mem, mpointer}",
|
|
"morel moshortestpathd [startNode,endNode,resultSelect; fun] ",
|
|
"Caculates the shortest path from startNode to endNode in a graph "
|
|
"representent in a ordered memory relation using dijkstras algorithm."
|
|
"The ordered relation must have SourceNodes as the first attribute and "
|
|
"target nodes as second attribute. "
|
|
"Using the argument resultselect, the output of this operator is "
|
|
"controlled. 0 : shortest path, 1 : remaining elements in queue, "
|
|
" 2 : visited sections, 3 : shortest path tree ",
|
|
"query mwrap('otestrel') moshortestpathd"
|
|
"[1,3,0; distance(.GeoData_s1,.GeoData_s2)] count"
|
|
);
|
|
|
|
/*
|
|
7.27.4 Instance of operator ~moshortestpathd~
|
|
|
|
*/
|
|
Operator moshortestpathdOp (
|
|
"moshortestpathd",
|
|
moshortestpathdSpec.getStr(),
|
|
2,
|
|
moshortestpathdVM,
|
|
moshortestpathSelect,
|
|
moshortestpathTypeMap<DIJKSTRA>
|
|
);
|
|
|
|
|
|
class moshortestpathaInfo {
|
|
public:
|
|
|
|
moshortestpathaInfo(ttree::TTree<TupleWrap,TupleComp>* _tree,
|
|
int _startNode, int _endNode, int _resultSelect,
|
|
Word& _arg, Word& _arg2, TupleType* _tt)
|
|
: mmorel(_tree),startNode(_startNode),
|
|
endNode(_endNode),resultSelect(_resultSelect),
|
|
arg(_arg),arg2(_arg2),tt(_tt),seqNo(1) {
|
|
|
|
queue = new Queue();
|
|
visitedNodes = new ttree::TTree<QueueEntryWrap,EntryComp>(16,18);
|
|
sptree = new ttree::TTree<TupleWrap,TupleComp>(16,18);
|
|
result = new ttree::TTree<TupleWrap,TupleComp>(16,18);
|
|
|
|
bool found = shortestPath();
|
|
if(found || resultSelect == 3) {
|
|
resultSelection();
|
|
}
|
|
else
|
|
cerr << "no path found" << endl;
|
|
|
|
iterator = result->begin();
|
|
}
|
|
|
|
~moshortestpathaInfo() {
|
|
while(!queue->empty())
|
|
queue->pop();
|
|
delete queue;
|
|
|
|
tt->DeleteIfAllowed();
|
|
tt = 0;
|
|
|
|
delete visitedNodes;
|
|
delete result;
|
|
delete sptree;
|
|
};
|
|
|
|
Tuple* next() {
|
|
if(iterator.end())
|
|
return 0;
|
|
Tuple* res = (*iterator).getPointer();
|
|
if(res==NULL) {
|
|
return 0;
|
|
}
|
|
iterator++;
|
|
res->IncReference();
|
|
return res;
|
|
}
|
|
|
|
|
|
/*
|
|
~shortestpath~
|
|
|
|
*/
|
|
bool shortestPath() {
|
|
|
|
// INIT
|
|
int toNode = startNode;
|
|
|
|
QueueEntry* startEntry = new QueueEntry(startNode,-1,0.0,0.0);
|
|
QueueEntryWrap qw(startEntry);
|
|
queue->push(qw);
|
|
visitedNodes->insert(qw);
|
|
startEntry->DeleteIfAllowed();
|
|
|
|
double dist = 0.0;
|
|
|
|
// SEARCH SHORTESTPATH
|
|
while(!queue->empty()) {
|
|
current = queue->top();
|
|
current()->visited = true;
|
|
queue->pop();
|
|
|
|
if (resultSelect<3 && current()->nodeNumber == endNode) {
|
|
return true;
|
|
}
|
|
else {
|
|
CcInt* currentNodeNumber = new CcInt(true,current()->nodeNumber);
|
|
|
|
ttree::Iterator<TupleWrap,TupleComp> it = mmorel->begin();
|
|
while(!it.end()) {
|
|
Tuple* tup = (*it).getPointer();
|
|
// get tuple with currentNodeNumber as startnode
|
|
if(tup->GetAttribute(0)->Compare(currentNodeNumber) < 0) {
|
|
it++;
|
|
}
|
|
else break;
|
|
}
|
|
|
|
while(!it.end()) {
|
|
Tuple* currentTuple = (*it).getPointer();
|
|
if(currentTuple->GetAttribute(0)->Compare(currentNodeNumber) > 0) {
|
|
break;
|
|
}
|
|
toNode = ((CcInt*)currentTuple->GetAttribute(1))->GetIntval();
|
|
if(resultSelect!=3) {
|
|
TupleWrap tw(currentTuple);
|
|
sptree->insert(tw);
|
|
}
|
|
if(current()->nodeNumber != toNode) {
|
|
ArgVectorPointer funArgs = qp->Argument(arg.addr);
|
|
funResult.addr =0;
|
|
((*funArgs)[0]).setAddr(currentTuple);
|
|
qp->Request(arg.addr,funResult);
|
|
double edgeCost = ((CcReal*)funResult.addr)->GetRealval();
|
|
if (edgeCost < 0.0) {
|
|
cerr << "Found negativ edge cost computation aborted." << endl;
|
|
return 0;
|
|
}
|
|
dist = current()->dist + edgeCost;
|
|
|
|
ArgVectorPointer funArgs2 = qp->Argument(arg2.addr);
|
|
funResult2.addr = 0;
|
|
((*funArgs2)[0]).setAddr(currentTuple);
|
|
qp->Request(arg2.addr,funResult2);
|
|
double restCost = ((CcReal*)funResult2.addr)->GetRealval();
|
|
if (restCost < 0) restCost = 0;
|
|
double prio = dist + restCost;
|
|
|
|
bool contained = false;
|
|
ttree::Iterator<QueueEntryWrap,EntryComp> it =
|
|
visitedNodes->begin();
|
|
while(!it.end()) {
|
|
QueueEntryWrap entry = *it;
|
|
// found node before
|
|
if(entry()->nodeNumber == toNode) {
|
|
if(entry()->priority > prio) {
|
|
QueueEntry* prevEntry = new QueueEntry(entry()->nodeNumber,
|
|
entry()->prev,
|
|
entry()->dist,
|
|
entry()->priority);
|
|
prevEntry->visited = entry()->visited;
|
|
entry()->prev = current()->nodeNumber;
|
|
entry()->priority = prio;
|
|
entry()->dist = dist;
|
|
if(entry()->visited){
|
|
QueueEntryWrap qw(prevEntry);
|
|
visitedNodes->update(entry,qw);
|
|
}
|
|
prevEntry->DeleteIfAllowed();
|
|
}
|
|
contained = true;
|
|
break;
|
|
}
|
|
it++;
|
|
}
|
|
|
|
if(!contained) {
|
|
QueueEntry* to =
|
|
new QueueEntry(toNode,current()->nodeNumber,dist,prio);
|
|
QueueEntryWrap qw(to);
|
|
visitedNodes->insert(qw,true);
|
|
to->DeleteIfAllowed();
|
|
queue->push(qw);
|
|
if(resultSelect==3) {
|
|
TupleWrap tw(currentTuple);
|
|
sptree->insert(tw);
|
|
}
|
|
currentTuple->IncReference();
|
|
}
|
|
}
|
|
it++;
|
|
}
|
|
currentNodeNumber->DeleteIfAllowed();
|
|
}
|
|
} // end while search shortestpath
|
|
return false;
|
|
}
|
|
|
|
|
|
void resultSelection() {
|
|
switch(resultSelect) {
|
|
case 0: { // shortest path
|
|
Tuple* currentTuple = findTuple(mmorel,
|
|
current()->nodeNumber,
|
|
current()->prev);
|
|
bool found = false;
|
|
|
|
int i=0;
|
|
while (!found && currentTuple != 0) {
|
|
|
|
i++;
|
|
appendTuple(currentTuple,tt,seqNo,result);
|
|
seqNo++;
|
|
|
|
if(current()->prev != startNode) {
|
|
current = findNextNode(visitedNodes,current);
|
|
currentTuple = findTuple(mmorel,
|
|
current()->nodeNumber,
|
|
current()->prev);
|
|
}
|
|
else {
|
|
found = true;
|
|
if(currentTuple != 0) {
|
|
currentTuple->DeleteIfAllowed();
|
|
currentTuple = 0;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 1: { //Remaining elements in priority queue
|
|
while(queue->size() > 0) {
|
|
current = queue->top();
|
|
queue->pop();
|
|
Tuple* currentTuple = findTuple(mmorel,
|
|
current()->nodeNumber,
|
|
current()->prev);
|
|
appendTuple(currentTuple,tt,seqNo,result);
|
|
seqNo++;
|
|
}
|
|
break;
|
|
}
|
|
case 2: { //visited sections
|
|
ttree::Iterator<TupleWrap,TupleComp> it = sptree->begin();
|
|
while(!it.end()) {
|
|
Tuple* currentTuple = (*it).getPointer();;
|
|
appendTuple(currentTuple,tt,seqNo,result);
|
|
seqNo++;
|
|
it++;
|
|
}
|
|
break;
|
|
}
|
|
case 3: { //shortest path tree
|
|
ttree::Iterator<TupleWrap,TupleComp> iter = sptree->begin();
|
|
while(!iter.end()) {
|
|
Tuple* currentTuple = (*iter).getPointer();
|
|
appendTuple(currentTuple,tt,seqNo,result);
|
|
iter++;
|
|
seqNo++;
|
|
}
|
|
break;
|
|
}
|
|
|
|
default: { //should have never been reached
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
protected:
|
|
|
|
ttree::TTree<TupleWrap,TupleComp>* mmorel;
|
|
ttree::Iterator<TupleWrap,TupleComp> iterator;
|
|
int startNode;
|
|
int endNode;
|
|
int resultSelect;
|
|
Word arg;
|
|
Word arg2;
|
|
TupleType* tt;
|
|
int seqNo;
|
|
Queue* queue;
|
|
|
|
ttree::TTree<QueueEntryWrap,EntryComp>* visitedNodes;
|
|
ttree::TTree<TupleWrap,TupleComp>* sptree;
|
|
ttree::TTree<TupleWrap,TupleComp>* result;
|
|
|
|
|
|
QueueEntryWrap current;
|
|
int seqNoAttrIndex;
|
|
|
|
private:
|
|
Word funResult;
|
|
Word funResult2;
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
7.28.2 Value Mapping Functions of operator ~moshortestpatha~
|
|
|
|
*/
|
|
template<class T>
|
|
int moshortestpathaValueMap(Word* args, Word& result, int message,
|
|
Word& local, Supplier s) {
|
|
|
|
moshortestpathaInfo* li = (moshortestpathaInfo*) local.addr;
|
|
|
|
switch(message) {
|
|
|
|
case OPEN: {
|
|
|
|
if(li) {
|
|
delete li;
|
|
local.addr=0;
|
|
}
|
|
|
|
int resultSelect = ((CcInt*) args[3].addr)->GetIntval();
|
|
if(resultSelect<0 || resultSelect>3) {
|
|
cerr << "Selected result value does not exist. Enter 0 for shortest "
|
|
<< "path, 1 for remaining priority queue elements, 2 for visited "
|
|
<< "edges, 3 for shortest path tree." << endl;
|
|
return 0;
|
|
}
|
|
|
|
// Check for simplest Case
|
|
int startNode = ((CcInt*)args[1].addr)->GetIntval();
|
|
int endNode = ((CcInt*)args[2].addr)->GetIntval();
|
|
if(resultSelect<3) {
|
|
if(startNode == endNode) {
|
|
cerr << "source and target node are equal, no path";
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
ListExpr tupleType = GetTupleResultType(s);
|
|
TupleType* tt = new TupleType(nl->Second(tupleType));
|
|
|
|
T* orelN = (T*) args[0].addr;
|
|
MemoryORelObject* orel = getMemORel(orelN, nl->Second(qp->GetType(s)));
|
|
if(!orel){
|
|
return 0;
|
|
}
|
|
|
|
local.addr = new moshortestpathaInfo(orel->getmmorel(),
|
|
startNode,
|
|
endNode,
|
|
resultSelect,
|
|
args[4], args[5], 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 0;
|
|
}
|
|
|
|
|
|
ValueMapping moshortestpathaVM[] = {
|
|
moshortestpathaValueMap<Mem>,
|
|
moshortestpathaValueMap<MPointer>,
|
|
|
|
};
|
|
|
|
/*
|
|
|
|
7.28.4 Description of operator ~moshortestpatha~
|
|
|
|
*/
|
|
OperatorSpec moshortestpathaSpec(
|
|
"MOREL x int x int x int x "
|
|
"(tuple->real) x (tuple->real)-> stream(tuple(a1:t1,...an+1:tn+1)), "
|
|
"MOREL in {mem, mpointer}",
|
|
"_ moshortestpatha [_,_,_; fun,fun] implicit parameter tuple type MTUPLE",
|
|
"calculates the shortest path for a given start and goal node in a main "
|
|
"memory ordered relation using the astar algorithm",
|
|
"query mwrap('otestrel') moshortestpatha [1,3,0; "
|
|
"distance(.GeoData_s1,.GeoData_s2), "
|
|
"distance(.GeoData_s1,.GeoData_s2) * 0.0] count"
|
|
);
|
|
|
|
/*
|
|
|
|
7.28.5 Instance of operator ~moshortestpatha~
|
|
|
|
*/
|
|
Operator moshortestpathaOp (
|
|
"moshortestpatha",
|
|
moshortestpathaSpec.getStr(),
|
|
2,
|
|
moshortestpathaVM,
|
|
moshortestpathSelect,
|
|
moshortestpathTypeMap<ASTAR>
|
|
);
|
|
|
|
|
|
|
|
|
|
/*
|
|
7.30 Operator ~moconnectedcomponents~
|
|
|
|
The operator ~moconnectedcomponents~ calculates the strongly connected
|
|
components in a graph given here as a main memory ordered relation.
|
|
The operator expects a main memory ordered relation with its tuples
|
|
containing at least two integers. They have to be ordered first by the start
|
|
node of each edge and secondly bey the end node.
|
|
|
|
The output is a tuple stream containing all tuples of the main memory
|
|
ordered relation with an additional attribute 'compNo' of type integer.
|
|
|
|
|
|
7.30.1 Type Mapping Funktion for operator ~moconnectedcomponents~
|
|
|
|
{string, mem(orel(tuple(x)))} -> stream(tuple(x@[compNo:int]))
|
|
|
|
*/
|
|
ListExpr moconnectedcomponentsTypeMap(ListExpr args) {
|
|
|
|
if(nl->ListLength(args) != 1) {
|
|
return listutils::typeError("one arguments expected");
|
|
}
|
|
|
|
ListExpr arg;
|
|
if(!getMemSubType(nl->First(args),arg)){
|
|
return listutils::typeError("first arg is not a memory object");
|
|
}
|
|
if(!listutils::isOrelDescription(arg)){
|
|
return listutils::typeError("memory object is not a relation");
|
|
}
|
|
|
|
ListExpr rest = nl->Second(nl->Second(arg));
|
|
ListExpr listn = nl->OneElemList(nl->First(rest));
|
|
ListExpr lastlistn = listn;
|
|
rest = nl->Rest(rest);
|
|
while (!(nl->IsEmpty(rest))) {
|
|
lastlistn = nl->Append(lastlistn,nl->First(rest));
|
|
rest = nl->Rest(rest);
|
|
}
|
|
|
|
lastlistn = nl->Append(lastlistn,
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom("CompNo"),
|
|
listutils::basicSymbol<CcInt>()));
|
|
|
|
ListExpr outList = nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()),
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom(Tuple::BasicType()),
|
|
listn));
|
|
return outList;
|
|
}
|
|
|
|
class Vertex {
|
|
public:
|
|
Vertex(int _nr)
|
|
: nr(_nr), inStack(false) {}
|
|
|
|
size_t operator()(const Vertex &v) const {
|
|
return v.nr;
|
|
}
|
|
|
|
void setIndex(int _index) {
|
|
index = _index;
|
|
}
|
|
|
|
void setLowlink(int _lowlink) {
|
|
lowlink = _lowlink;
|
|
}
|
|
|
|
int nr;
|
|
int index;
|
|
int lowlink;
|
|
int compNo;
|
|
bool inStack;
|
|
};
|
|
|
|
class VertexComp {
|
|
public:
|
|
bool operator()(const Vertex& v1, const Vertex& v2) const {
|
|
return v1.nr < v2.nr;
|
|
}
|
|
};
|
|
|
|
// geaendert 9.9.2016
|
|
class moconnectedComponentsInfo{
|
|
public:
|
|
moconnectedComponentsInfo(ttree::TTree<TupleWrap,TupleComp>* _tree,
|
|
ListExpr _tt)
|
|
: tree(_tree) {
|
|
tt = new TupleType(_tt);
|
|
|
|
scctree = new ttree::TTree<TupleWrap,TupleComp>(16,18);
|
|
nodes = new set<Vertex,VertexComp>();
|
|
scc(tree);
|
|
appendTuples();
|
|
iter = scctree->begin();
|
|
}
|
|
|
|
|
|
~moconnectedComponentsInfo(){
|
|
delete scctree;
|
|
//set<Vertex,VertexComp>::iterator it = nodes->begin();
|
|
delete nodes;
|
|
tt->DeleteIfAllowed();
|
|
}
|
|
|
|
|
|
Tuple* next() {
|
|
if(iter.end())
|
|
return 0;
|
|
Tuple* res = (*iter).getPointer();
|
|
if(!res) {
|
|
return 0;
|
|
}
|
|
iter++;
|
|
res->IncReference();
|
|
return res;
|
|
}
|
|
|
|
// appends all tuples including their component number to scctree
|
|
bool appendTuples() {
|
|
set<Vertex,VertexComp>::iterator iter;
|
|
ttree::Iterator<TupleWrap,TupleComp> it = tree->begin();
|
|
while(!it.end()) {
|
|
Tuple* t = (*it).getPointer();
|
|
Vertex v(((CcInt*)t->GetAttribute(1))->GetIntval());
|
|
iter = nodes->find(v);
|
|
if(iter != nodes->end()) {
|
|
v = *iter;
|
|
Tuple* newTuple = new Tuple(tt);
|
|
for(int i=0; i<t->GetNoAttributes(); i++) {
|
|
newTuple->CopyAttribute(i,t,i);
|
|
}
|
|
CcInt* noOfNodes = new CcInt(true, v.compNo);
|
|
newTuple->PutAttribute(t->GetNoAttributes(),noOfNodes);
|
|
TupleWrap tw(newTuple);
|
|
scctree->insert(tw,t->GetNoAttributes()); // sort by CompNo
|
|
newTuple->DeleteIfAllowed();
|
|
}
|
|
else return false;
|
|
it++;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
void scc(ttree::TTree<TupleWrap,TupleComp>* tree) {
|
|
int compNo = 1;
|
|
int index = 0;
|
|
ttree::Iterator<TupleWrap,TupleComp> it = tree->begin();
|
|
std::stack<Vertex>* stack = new std::stack<Vertex>();
|
|
// process first node
|
|
Tuple* tuple = (*it).getPointer();
|
|
scc(tuple,index,stack,compNo);
|
|
|
|
// process nodes
|
|
while(!it.end()) {
|
|
// find next node
|
|
Tuple* t = (*it).getPointer();
|
|
while(t->GetAttribute(0)->Compare(tuple->GetAttribute(0)) == 0) {
|
|
it++;
|
|
if(!it.end()) {
|
|
tuple = (*it).getPointer();
|
|
}
|
|
// all nodes processed
|
|
else {
|
|
delete stack;
|
|
return;
|
|
}
|
|
}
|
|
// find scc for node
|
|
scc(tuple,index,stack,compNo);
|
|
}
|
|
|
|
}
|
|
|
|
// caculates the scc for each node
|
|
void scc(Tuple* tuple, int& index,
|
|
std::stack<Vertex>* stack, int& compNo) {
|
|
|
|
set<Vertex,VertexComp>::iterator iter;
|
|
Vertex v(((CcInt*)tuple->GetAttribute(0))->GetIntval());
|
|
iter = nodes->find(v);
|
|
|
|
// v already seen
|
|
if(iter != nodes->end()) {
|
|
return;
|
|
}
|
|
|
|
// v not yet seen
|
|
v.index = index;
|
|
v.lowlink = index;
|
|
index++;
|
|
stack->push(v);
|
|
v.inStack = true;
|
|
nodes->insert(v);
|
|
ttree::Iterator<TupleWrap,TupleComp> it = tree->begin();
|
|
Tuple* t = (*it).getPointer();
|
|
|
|
// find node in orel
|
|
while(t->GetAttribute(0)->Compare(tuple->GetAttribute(0)) < 0) {
|
|
it++;
|
|
if(!it.end())
|
|
t = (*it).getPointer();
|
|
else return;
|
|
}
|
|
|
|
// while node has adjacent nodes
|
|
while(((CcInt*)t->GetAttribute(0))->GetIntval() == v.nr) {
|
|
Vertex w(((CcInt*)t->GetAttribute(1))->GetIntval());
|
|
iter = nodes->find(w);
|
|
// w not seen yet
|
|
if(iter == nodes->end()) {
|
|
it = tree->begin();
|
|
t = (*it).getPointer();
|
|
while(((CcInt*)t->GetAttribute(0))->GetIntval() != w.nr) {
|
|
it++;
|
|
if(!it.end())
|
|
t = (*it).getPointer();
|
|
// no adjacent nodes for this node
|
|
else {
|
|
t = tuple;
|
|
w.index = index;
|
|
w.lowlink = index;
|
|
w.compNo = compNo;
|
|
compNo++;
|
|
index++;
|
|
nodes->insert(w);
|
|
break;
|
|
}
|
|
}
|
|
// recursive call
|
|
scc(t,index,stack,compNo);
|
|
iter = nodes->find(w);
|
|
w = *iter;
|
|
v.setLowlink(min(v.lowlink,w.lowlink));
|
|
// find next adjacent edge for v
|
|
it = tree->begin();
|
|
t = (*it).getPointer();
|
|
while(t->GetAttribute(0)->Compare(tuple->GetAttribute(0)) < 0) {
|
|
it++;
|
|
if(!it.end())
|
|
t = (*it).getPointer();
|
|
else return;
|
|
}
|
|
}
|
|
// w already seen
|
|
else {
|
|
w = *iter;
|
|
if(w.inStack) {
|
|
v.setLowlink(min(v.lowlink,w.index));
|
|
}
|
|
}
|
|
it++;
|
|
if(!it.end())
|
|
t = (*it).getPointer();
|
|
else break;
|
|
}
|
|
|
|
// root of scc found
|
|
if (v.lowlink == v.index) {
|
|
v.compNo = compNo;
|
|
while(true) {
|
|
Vertex w = stack->top();
|
|
stack->pop();
|
|
w.inStack = false;
|
|
if(v.nr == w.nr)
|
|
break;
|
|
w.compNo = compNo;
|
|
}
|
|
compNo++;
|
|
}
|
|
}
|
|
|
|
private:
|
|
ttree::TTree<TupleWrap,TupleComp>* tree;
|
|
ttree::TTree<TupleWrap,TupleComp>* scctree;
|
|
set<Vertex,VertexComp>* nodes;
|
|
ttree::Iterator<TupleWrap,TupleComp> iter;
|
|
TupleType* tt;
|
|
};
|
|
|
|
|
|
/*
|
|
|
|
7.30.2 Value Mapping Functions of operator ~moconnectedcomponents~
|
|
|
|
*/
|
|
template<class T>
|
|
int moconnectedcomponentsValMap (Word* args, Word& result,
|
|
int message, Word& local, Supplier s) {
|
|
|
|
moconnectedComponentsInfo* li = (moconnectedComponentsInfo*) local.addr;
|
|
|
|
switch (message) {
|
|
case OPEN: {
|
|
|
|
if(li){
|
|
delete li;
|
|
local.addr=0;
|
|
}
|
|
T* oN = (T*) args[0].addr;
|
|
|
|
ListExpr ttype = nl->Second(nl->Second(qp->GetType(s)));
|
|
|
|
MemoryORelObject* orel = getMemORel(oN,ttype);
|
|
if(!orel){
|
|
return listutils::typeError
|
|
("could not find memory orel object");
|
|
}
|
|
|
|
ListExpr tupleType = GetTupleResultType(s);
|
|
ListExpr tt = nl->Second(tupleType);
|
|
|
|
local.addr= new moconnectedComponentsInfo(orel->getmmorel(),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 -1;
|
|
}
|
|
|
|
|
|
ValueMapping moconnectedcomponentsVM[] = {
|
|
moconnectedcomponentsValMap<Mem>,
|
|
moconnectedcomponentsValMap<MPointer>
|
|
|
|
};
|
|
|
|
int moconnectedcomponentsSelect(ListExpr args){
|
|
return Mem::checkType(nl->First(args))?0:1;;
|
|
}
|
|
|
|
|
|
/*
|
|
|
|
7.30.4 Description of operator ~moconnectedcomponents~
|
|
|
|
*/
|
|
OperatorSpec moconnectedcomponentsSpec(
|
|
"MOREL -> stream(Tuple)",
|
|
"_ moconnectedcomponents",
|
|
"",
|
|
"query motestrel moconnectedcomponents"
|
|
);
|
|
|
|
/*
|
|
|
|
7.30.5 Instance of operator ~moconnectedcomponents~
|
|
|
|
*/
|
|
Operator moconnectedcomponentsOp (
|
|
"moconnectedcomponents",
|
|
moconnectedcomponentsSpec.getStr(),
|
|
2,
|
|
moconnectedcomponentsVM,
|
|
moconnectedcomponentsSelect,
|
|
moconnectedcomponentsTypeMap
|
|
);
|
|
|
|
|
|
/*
|
|
7.31 Operators ~mquicksort~ and ~mquicksortby~
|
|
|
|
The Operator ~mquicksort~ sorts all tuples of a main memory relation
|
|
over all of their attributes, as long as they are atomic. It returns
|
|
the tuples with an additional attribut of type 'tid' in an output stream.
|
|
|
|
The Operator ~mquicksortby~ sorts all the elements in a main memory relation
|
|
by one or more given attributes and returns a stream of the sorted tuples
|
|
and their original tupleid's.
|
|
|
|
7.31.1 Type Mapping Functions of operator ~mquicksort~ and ~mquicksortby~
|
|
|
|
{string, mem(rel(tuple(x)))} -> stream(tuple(x)) or
|
|
{string, mem(rel(tuple(x)))} x (ident1 ... identn) -> stream(tuple(x))
|
|
|
|
*/
|
|
enum SORTTYPE{
|
|
Sort,
|
|
SortBy
|
|
};
|
|
|
|
template<SORTTYPE st>
|
|
ListExpr mquicksortTypeMap(ListExpr args) {
|
|
|
|
if(st == Sort) {
|
|
if(nl->ListLength(args) != 1)
|
|
return listutils::typeError("one argument expected");
|
|
}
|
|
if(st == SortBy) {
|
|
if(nl->ListLength(args) != 2)
|
|
return listutils::typeError("two arguments expected");
|
|
}
|
|
|
|
// check relation
|
|
ListExpr first;
|
|
if(!getMemSubType(nl->First(args),first)){
|
|
return listutils::typeError("first arg is not a memory object");
|
|
}
|
|
if(!Relation::checkType(first)){
|
|
return listutils::typeError("memory object is not a relation");
|
|
}
|
|
|
|
// check if second argument attribute of relation
|
|
if(st == SortBy) {
|
|
int numberOfSortAttrs = nl->ListLength(nl->Second(args));
|
|
if(numberOfSortAttrs <= 0){
|
|
return listutils::typeError("Attribute list may not be empty!");
|
|
}
|
|
|
|
if(!listutils::isKeyDescription(nl->Second(first),
|
|
nl->Second(args))) {
|
|
return listutils::typeError("all identifiers of second argument must "
|
|
"appear in the first argument");
|
|
}
|
|
}
|
|
|
|
return nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()),
|
|
nl->Second(first));
|
|
}
|
|
|
|
|
|
/*
|
|
|
|
7.31.2 The Value Mapping Functions of operators ~mquicksort~ and
|
|
~mquicksortby~
|
|
|
|
*/
|
|
class mquicksortInfo{
|
|
public:
|
|
mquicksortInfo(vector<Tuple*>* _relation, vector<int> _pos)
|
|
: relation(_relation), pos(_pos) {
|
|
|
|
quicksort(0,relation->size()-1,pos);
|
|
it = relation->begin();
|
|
}
|
|
|
|
~mquicksortInfo(){}
|
|
|
|
void quicksort(int left, int right, vector<int> pos) {
|
|
|
|
int i = left, j = right;
|
|
Tuple* tmp;
|
|
Tuple* pivot = relation->at(((left + right) / 2));
|
|
|
|
/* partition */
|
|
while (i <= j) {
|
|
|
|
while(TupleComp::smaller(relation->at(i),pivot,&pos))
|
|
i++;
|
|
while (TupleComp::greater(relation->at(j),pivot,&pos))
|
|
j--;
|
|
|
|
if (i <= j) {
|
|
tmp = relation->at(i);
|
|
relation->at(i) = relation->at(j);
|
|
relation->at(j) = tmp;
|
|
|
|
i++;
|
|
j--;
|
|
}
|
|
}
|
|
/* recursion */
|
|
if (left < j)
|
|
quicksort(left, j, pos);
|
|
if (i < right)
|
|
quicksort(i, right, pos);
|
|
}
|
|
|
|
|
|
Tuple* next() {
|
|
while(it != relation->end()){
|
|
Tuple* res = *it;
|
|
it++;
|
|
if(res) {
|
|
res->IncReference();
|
|
return res;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
private:
|
|
vector<Tuple*>* relation;
|
|
vector<int> pos;
|
|
vector<Tuple*>::iterator it;
|
|
};
|
|
|
|
/*
|
|
|
|
7.31.2 Value Mapping Function of operators ~mquicksort~ and ~mquicksortby~
|
|
|
|
*/
|
|
template<class T, SORTTYPE st>
|
|
int mquicksortValMap (Word* args, Word& result,
|
|
int message, Word& local, Supplier s) {
|
|
|
|
mquicksortInfo* li = (mquicksortInfo*) local.addr;
|
|
|
|
switch (message) {
|
|
case OPEN: {
|
|
|
|
if(li){
|
|
delete li;
|
|
local.addr=0;
|
|
}
|
|
vector<int> pos;
|
|
T* oN = (T*) args[0].addr;
|
|
|
|
MemoryRelObject* rel = getMemRel(oN, nl->Second(qp->GetType(s)));
|
|
if(!rel){
|
|
return listutils::typeError
|
|
("could not find memory rel object");
|
|
}
|
|
|
|
if(st == SortBy) {
|
|
Supplier t = qp->GetSon(s,0);
|
|
ListExpr listrel = nl->Second(qp->GetType(s));
|
|
t = qp->GetSon(s,1);
|
|
ListExpr attrToSort = qp->GetType(t);
|
|
ListExpr attr;
|
|
while (!(nl->IsEmpty(attrToSort))) {
|
|
attr = nl->First(attrToSort);
|
|
attrToSort = nl->Rest(attrToSort);
|
|
|
|
ListExpr attrType = 0;
|
|
int attrPos = 0;
|
|
ListExpr attrList = nl->Second(listrel);
|
|
|
|
attrPos = listutils::findAttribute(attrList,
|
|
nl->ToString(attr),
|
|
attrType);
|
|
if(attrPos == 0) {
|
|
return listutils::typeError
|
|
("there is no attribute having name " + nl->ToString(attr));
|
|
}
|
|
pos.push_back(attrPos);
|
|
}
|
|
}
|
|
else if(st == Sort) {
|
|
ListExpr listrel = nl->Second(nl->Second(qp->GetType(s)));
|
|
for(int i=0; i<nl->ListLength(listrel); i++)
|
|
pos.push_back(i+1);
|
|
}
|
|
|
|
local.addr= new mquicksortInfo(rel->getmmrel(),pos);
|
|
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;
|
|
}
|
|
|
|
|
|
ValueMapping mquicksortVM[] = {
|
|
mquicksortValMap<Mem,Sort>,
|
|
mquicksortValMap<MPointer,Sort>,
|
|
mquicksortValMap<Mem,SortBy>,
|
|
mquicksortValMap<MPointer,SortBy>,
|
|
};
|
|
|
|
template<SORTTYPE st>
|
|
int mquicksortSelect(ListExpr args){
|
|
int num = Mem::checkType(nl->First(args))?0:1;;
|
|
if(num<0) return -1;
|
|
return st==Sort?num:num+2;
|
|
}
|
|
|
|
|
|
/*
|
|
7.31.4 Description of operator ~mquicksort~
|
|
|
|
*/
|
|
OperatorSpec mquicksortSpec(
|
|
"MREL -> stream(Tuple), MREL in {mem, mpointer}",
|
|
"_ mquicksort",
|
|
"sorts all elements of a main memory relation over all attributes",
|
|
"query 'Staedte' mquicksort count"
|
|
);
|
|
|
|
/*
|
|
7.31.5 Instance of operator ~mquicksort~
|
|
|
|
*/
|
|
Operator mquicksortOp (
|
|
"mquicksort",
|
|
mquicksortSpec.getStr(),
|
|
4,
|
|
mquicksortVM,
|
|
mquicksortSelect<Sort>,
|
|
mquicksortTypeMap<Sort>
|
|
);
|
|
|
|
/*
|
|
|
|
7.32.4 Description of operator ~mquicksortby~
|
|
|
|
*/
|
|
OperatorSpec mquicksortbySpec(
|
|
"MREL x ID -> stream(Tuple), MREL on {mem, mpointer}",
|
|
"_ mquicksortby[]",
|
|
"sorts the main memory over the given attributes",
|
|
"query 'Staedte' mquicksortby[Bev,SName] count"
|
|
);
|
|
|
|
/*
|
|
|
|
7.32.5 Instance of operator ~mquicksortby~
|
|
|
|
*/
|
|
Operator mquicksortbyOp (
|
|
"mquicksortby",
|
|
mquicksortbySpec.getStr(),
|
|
4,
|
|
mquicksortVM,
|
|
mquicksortSelect<SortBy>,
|
|
mquicksortTypeMap<SortBy>
|
|
);
|
|
|
|
/////////////////////////////////////// GRAPH ////
|
|
|
|
|
|
/*
|
|
|
|
~dijkstra~
|
|
|
|
Calculates the shortest path between the vertices __start__ and
|
|
__dest__ in the __graph__ using dijkstra's algorithm.
|
|
|
|
*/
|
|
bool dijkstra(graph::Graph* graph, Word& arg,
|
|
graph::Vertex* start, graph::Vertex* dest) {
|
|
|
|
graph::Queue queue;
|
|
|
|
set<graph::Vertex*,graph::Vertex::EqualVertex>::iterator it =
|
|
graph->getGraph()->begin();
|
|
// init all nodes
|
|
while(it != graph->getGraph()->end()) {
|
|
graph::Vertex* v = *it;
|
|
v->setCost(numeric_limits<double>::max());
|
|
v->isSeen(false);
|
|
v->setDist(0);
|
|
v->setPrev(0);
|
|
it++;
|
|
}
|
|
|
|
// cost to start node
|
|
start->setCost(0);
|
|
queue.push(start);
|
|
|
|
Word funResult;
|
|
|
|
// as long as queue has entries
|
|
while(!queue.empty()) {
|
|
graph::Vertex* v = queue.top();
|
|
queue.pop();
|
|
if(v->wasSeen()) continue;
|
|
v->isSeen(true);
|
|
|
|
// process edges
|
|
for(size_t i=0; i<v->getEdges()->size(); i++) {
|
|
|
|
vector<graph::EdgeWrap>* edges = v->getEdges();
|
|
|
|
graph::Vertex* w = graph->getVertex(edges
|
|
->at(i).getPointer()->getDest());
|
|
|
|
ArgVectorPointer funArgs = qp->Argument(arg.addr);
|
|
funResult.addr = 0;
|
|
((*funArgs)[0]).setAddr(v->getEdges()->at(i).getPointer()->getTuple());
|
|
qp->Request(arg.addr,funResult);
|
|
double cost = ((CcReal*)funResult.addr)->GetRealval();
|
|
|
|
if(cost<0) {
|
|
std::cout << "Error: cost is negative" << std::endl;
|
|
return false;
|
|
}
|
|
|
|
// shortening of path possible
|
|
if(w->getCost() > v->getCost()+cost) {
|
|
w->setCost(v->getCost()+cost);
|
|
w->setDist(w->getCost());
|
|
w->setPrev(v);
|
|
queue.push(w);
|
|
}
|
|
|
|
}
|
|
if(v->getNr() == dest->getNr()) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
|
|
~astar~
|
|
|
|
Calculates the shortest path between the vertices __start__ and
|
|
__dest__ in the __graph__ using the AStar-algorithm.
|
|
|
|
*/
|
|
bool astar(graph::Graph* graph, Word& arg, Word& arg2,
|
|
graph::Vertex* start, graph::Vertex* dest) {
|
|
|
|
graph::Queue openlist;
|
|
|
|
set<graph::Vertex*,graph::Vertex::EqualVertex>::iterator it =
|
|
graph->getGraph()->begin();
|
|
while(it != graph->getGraph()->end()) {
|
|
graph::Vertex* v = *it;
|
|
v->setCost(numeric_limits<double>::max());
|
|
v->isSeen(false);
|
|
v->setDist(numeric_limits<double>::max());
|
|
v->setPrev(0);
|
|
it++;
|
|
}
|
|
|
|
// cost to start node
|
|
start->setCost(0.0);
|
|
openlist.push(start);
|
|
|
|
Word funResult;
|
|
Word funResult2;
|
|
|
|
|
|
// as long as queue has entries
|
|
while(!openlist.empty()) {
|
|
graph::Vertex* v = openlist.top();
|
|
openlist.pop();
|
|
if(v->wasSeen()) continue;
|
|
v->isSeen(true);
|
|
|
|
if(v->getNr() == dest->getNr()) {
|
|
return true;
|
|
}
|
|
|
|
// for every adjacent edge of v
|
|
for(size_t i=0; i<v->getEdges()->size(); i++) {
|
|
graph::Vertex* w = graph->getVertex(v->getEdges()
|
|
->at(i).getPointer()->getDest());
|
|
ArgVectorPointer funArgs = qp->Argument(arg.addr);
|
|
funResult.addr = 0;
|
|
((*funArgs)[0]).setAddr(v->getEdges()->at(i).getPointer()->getTuple());
|
|
qp->Request(arg.addr,funResult);
|
|
double edgecost = ((CcReal*)funResult.addr)->GetRealval();
|
|
|
|
if(edgecost<0.0) {
|
|
return false;
|
|
}
|
|
|
|
ArgVectorPointer funArgs2 = qp->Argument(arg2.addr);
|
|
funResult2.addr = 0;
|
|
((*funArgs2)[0]).setAddr(v->getEdges()->at(i).getPointer()->getTuple());
|
|
qp->Request(arg2.addr,funResult2);
|
|
double prio = ((CcReal*)funResult2.addr)->GetRealval();
|
|
|
|
if(prio<0.0) {
|
|
prio = 0.0;
|
|
}
|
|
|
|
// shortening of path possible
|
|
if(w->getDist() > v->getCost()+edgecost+prio) {
|
|
w->setCost(v->getCost()+edgecost);
|
|
w->setDist(prio+w->getCost());
|
|
|
|
if(!w->wasSeen())
|
|
w->setPrev(v);
|
|
openlist.push(w);
|
|
}
|
|
}
|
|
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool shortestPath(graph::Graph* graph, int startNode,
|
|
int endNode, Word& arg, Word& arg2,
|
|
bool isAstar) {
|
|
bool found = false;
|
|
if(!isAstar) {
|
|
found = dijkstra(graph, arg,
|
|
graph->getVertex(startNode),
|
|
graph->getVertex(endNode));
|
|
}
|
|
if(isAstar) {
|
|
found = astar(graph,arg,arg2,
|
|
graph->getVertex(startNode),
|
|
graph->getVertex(endNode));
|
|
}
|
|
if(found) {
|
|
graph->getPath(graph->getVertex(endNode));
|
|
}
|
|
return found;
|
|
}
|
|
|
|
/*
|
|
7.33 Operator ~mgshortestdpathd~
|
|
|
|
The Operator ~mgshortestpathd~ and ~mgshortestpatha~ calculate the shortest
|
|
path between two given nodes of a graph. The graph is in this case represented
|
|
by a main memory graph. The tuples of such a graph need to
|
|
have two integer values as their first two attributes identifying the start and
|
|
end node of an edge and at least one double value containing the cost
|
|
the edge.
|
|
|
|
The operator expects an main memory graph, two integers describing
|
|
the start and goal node of the path, an integer choosing the resulting output
|
|
of the shortest path calculation, as well as an cost function, which maps
|
|
the values of the tuples to a double value. The Operator ~moshortestpatha~
|
|
expects an additional function calculating the distance to the goal node.
|
|
|
|
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
|
|
|
|
For all cases an additional attribute 'seqNo' of type integer will be appended
|
|
to the tuples of the output stream.
|
|
|
|
The Operator ~mgshortestpathd~ uses Dijkstras Algorithm and the Operator
|
|
~mgshortestpatha~ uses the AStar-Algorithm.
|
|
|
|
|
|
7.33.1 General Type Mapping for Operators ~mgshortestpathd~ and
|
|
~mgshortestpatha~
|
|
|
|
{string, mem(rel(tuple(X)))} x int x int x int ->
|
|
stream(tuple(a1:t1,...an+1:tn+1)) and
|
|
|
|
{string, mem(graph(tuple(X)))} x int x int x int x (tuple->real)
|
|
x (tuple->real) ->
|
|
stream(tuple(a1:t1,...an+1:tn+1))
|
|
|
|
*/
|
|
template<bool isAstar>
|
|
ListExpr mgshortestpathdTypeMap(ListExpr args) {
|
|
|
|
if(!isAstar && nl->ListLength(args) != 5) {
|
|
return listutils::typeError("five arguments expected");
|
|
}
|
|
|
|
else if(isAstar && nl->ListLength(args) != 6) {
|
|
return listutils::typeError("six arguments expected");
|
|
}
|
|
|
|
ListExpr graph;
|
|
if(!getMemSubType(nl->First(args), graph)){
|
|
return listutils::typeError("first argument is not a memory object");
|
|
}
|
|
if(!MemoryGraphObject::checkType(graph)) {
|
|
return listutils::typeError("first arg is not a mem graph");
|
|
}
|
|
|
|
ListExpr startNodeList = nl->Second(args);
|
|
ListExpr endNodeList = nl->Third(args);
|
|
ListExpr resultSelect = nl->Fourth(args);
|
|
ListExpr map = nl->Fifth(args);
|
|
ListExpr distMap=nl->TheEmptyList();
|
|
if(isAstar)
|
|
distMap = nl->Sixth(args);
|
|
|
|
graph = nl->Second(graph);
|
|
|
|
if(!listutils::isTupleDescription(graph)) {
|
|
return listutils::typeError(
|
|
"second value of graph is not of type tuple");
|
|
}
|
|
|
|
ListExpr relAttrList(nl->Second(graph));
|
|
|
|
if(!listutils::isAttrList(relAttrList)) {
|
|
return listutils::typeError("Error in rel attrlist.");
|
|
}
|
|
|
|
if(!(nl->ListLength(relAttrList) >= 3)) {
|
|
return listutils::typeError("rel 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>(map)) {
|
|
return listutils::typeError("Fifth argument should be a map");
|
|
}
|
|
|
|
ListExpr mapTuple = nl->Second(map);
|
|
|
|
if(!nl->Equal(graph,mapTuple)) {
|
|
return listutils::typeError(
|
|
"Tuple of map function must match graph tuple");
|
|
}
|
|
|
|
ListExpr mapres = nl->Third(map);
|
|
|
|
if(!listutils::isSymbol(mapres,CcReal::BasicType())) {
|
|
return listutils::typeError(
|
|
"Wrong mapping result type for mgshortestpatha");
|
|
}
|
|
|
|
//Check of sixth argument if AStar
|
|
if(isAstar) {
|
|
if(!listutils::isMap<1>(distMap)) {
|
|
return listutils::typeError(
|
|
"Sixth argument should be a map");
|
|
}
|
|
|
|
ListExpr distmapTuple = nl->Second(distMap);
|
|
|
|
if(!nl->Equal(graph,distmapTuple)) {
|
|
return listutils::typeError(
|
|
"Tuple of map function must match graph tuple");
|
|
}
|
|
|
|
ListExpr distmapres = nl->Third(distMap);
|
|
|
|
if(!listutils::isSymbol(distmapres,CcReal::BasicType())) {
|
|
return listutils::typeError(
|
|
"Wrong mapping result type for mgshortestpatha");
|
|
}
|
|
}
|
|
|
|
// appends Attribute SeqNo to Attributes in orel
|
|
ListExpr rest = nl->Second(graph);
|
|
ListExpr listn = nl->OneElemList(nl->First(rest));
|
|
ListExpr lastlistn = listn;
|
|
rest = nl->Rest(rest);
|
|
while (!(nl->IsEmpty(rest))) {
|
|
lastlistn = nl->Append(lastlistn,nl->First(rest));
|
|
rest = nl->Rest(rest);
|
|
}
|
|
lastlistn = nl->Append(lastlistn,
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom("SeqNo"),
|
|
nl->SymbolAtom(TupleIdentifier::BasicType())));
|
|
|
|
return nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()),
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom(Tuple::BasicType()),
|
|
listn));
|
|
}
|
|
|
|
|
|
class mgshortestpathdInfo {
|
|
public:
|
|
|
|
mgshortestpathdInfo(graph::Graph* _graph,
|
|
int _startNode, int _endNode,
|
|
int _resultSelect, Word& _arg,
|
|
TupleType* _tt)
|
|
: graph(_graph),startNode(_startNode),
|
|
endNode(_endNode), resultSelect(_resultSelect),
|
|
arg(_arg), tt(_tt),seqNo(1) {
|
|
|
|
result = new ttree::TTree<TupleWrap,TupleComp>(16,18);
|
|
bool found = shortestPath(graph,startNode,endNode,arg,arg,false);
|
|
|
|
if(found || resultSelect == 3) {
|
|
resultSelection();
|
|
}
|
|
else {
|
|
cerr << "no path found" << endl;
|
|
}
|
|
iterator = result->begin();
|
|
|
|
}
|
|
|
|
~mgshortestpathdInfo() {
|
|
graph->reset();
|
|
delete result;
|
|
tt->DeleteIfAllowed();
|
|
}
|
|
|
|
Tuple* next() {
|
|
if(iterator.end())
|
|
return 0;
|
|
Tuple* res = (*iterator).getPointer();
|
|
if(res==NULL) {
|
|
return 0;
|
|
}
|
|
iterator++;
|
|
res->IncReference();
|
|
return res;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
~resultSelection~
|
|
|
|
*/
|
|
void resultSelection() {
|
|
|
|
switch(resultSelect) {
|
|
case 0: { // shortest path
|
|
|
|
seqNo = 1;
|
|
int source = startNode;
|
|
int dest = 0;
|
|
|
|
for(size_t i=1; i<graph->getResult()->size(); i++) {
|
|
dest = graph->getResult()->at(i);
|
|
Tuple* tup = graph->getEdge(source,dest);
|
|
if(!tup)
|
|
break;
|
|
|
|
appendTuple(tup,tt,seqNo,result);
|
|
seqNo++;
|
|
source = dest;
|
|
}
|
|
graph->reset();
|
|
break;
|
|
}
|
|
case 1: { //Remaining elements in priority queue
|
|
|
|
break;
|
|
}
|
|
|
|
case 2: { //visited sections
|
|
|
|
break;
|
|
}
|
|
|
|
case 3: { //shortest path tree
|
|
|
|
break;
|
|
}
|
|
|
|
default: { //should have never been reached
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
protected:
|
|
|
|
graph::Graph* graph;
|
|
int startNode;
|
|
int endNode;
|
|
int resultSelect;
|
|
Word arg;
|
|
TupleType* tt;
|
|
int seqNoAttrIndex;
|
|
int seqNo;
|
|
ttree::TTree<TupleWrap,TupleComp>* result;
|
|
ttree::Iterator<TupleWrap,TupleComp> iterator;
|
|
};
|
|
|
|
|
|
/*
|
|
|
|
7.33.2 Value Mapping Function of operator ~mgshortestpathd~
|
|
|
|
*/
|
|
template<class T>
|
|
int mgshortestpathdValMap (Word* args, Word& result,
|
|
int message, Word& local, Supplier s) {
|
|
|
|
mgshortestpathdInfo* li = (mgshortestpathdInfo*) local.addr;
|
|
|
|
switch (message) {
|
|
case OPEN: {
|
|
|
|
if(li){
|
|
delete li;
|
|
local.addr=0;
|
|
}
|
|
|
|
int resultSelect = ((CcInt*)args[3].addr)->GetIntval();
|
|
if(resultSelect<0 || resultSelect>3) {
|
|
cerr << "Selected result value does not exist. Enter 0 for shortest "
|
|
<< "path, 1 for remaining priority queue elements, 2 for visited "
|
|
<< "edges, 3 for shortest path tree." << endl;
|
|
return 0;
|
|
}
|
|
|
|
// Check for simplest Case
|
|
int startNode = ((CcInt*)args[1].addr)->GetIntval();
|
|
int endNode = ((CcInt*)args[2].addr)->GetIntval();
|
|
if(resultSelect<3) {
|
|
if(startNode == endNode) {
|
|
cerr << "source and target node are equal, no path";
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
T* oN = (T*) args[0].addr;
|
|
|
|
MemoryGraphObject* memgraph = getMemGraph(oN);
|
|
if(!memgraph) {
|
|
return 0;
|
|
}
|
|
|
|
ListExpr tupleType = GetTupleResultType(s);
|
|
TupleType* tt = new TupleType(nl->Second(tupleType));
|
|
|
|
local.addr = new mgshortestpathdInfo(memgraph->getgraph(),
|
|
startNode,
|
|
endNode,
|
|
resultSelect,
|
|
args[4],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 -1;
|
|
}
|
|
|
|
|
|
ValueMapping mgshortestpathdVM[] = {
|
|
mgshortestpathdValMap<Mem>,
|
|
mgshortestpathdValMap<MPointer>,
|
|
|
|
};
|
|
|
|
int mgshortestpathdSelect(ListExpr args){
|
|
return Mem::checkType(nl->First(args))?0:1;;
|
|
}
|
|
|
|
|
|
/*
|
|
|
|
7.33.4 Description of operator ~mgshortestpathd~
|
|
|
|
*/
|
|
OperatorSpec mgshortestpathdSpec(
|
|
"MGRAPH x int x int x int -> "
|
|
"stream(tuple(a1:t1,...an+1:tn+1))",
|
|
"_ mgshortestpathd [_,_,_; fun] implicit parameter tuple type MTUPLE",
|
|
"finds the shortest path between to given nodes in a main memory "
|
|
"graph using dijkstras algorithm",
|
|
"query graph mgshortestpathd "
|
|
"[1,3,0; distance(.GeoData_s1,.GeoData_s2)] count"
|
|
);
|
|
|
|
|
|
/*
|
|
|
|
7.33.5 Instance of operator ~mgshortestpathd~
|
|
|
|
*/
|
|
Operator mgshortestpathdOp (
|
|
"mgshortestpathd",
|
|
mgshortestpathdSpec.getStr(),
|
|
2,
|
|
mgshortestpathdVM,
|
|
mgshortestpathdSelect,
|
|
mgshortestpathdTypeMap<false>
|
|
);
|
|
|
|
|
|
|
|
class mgshortestpathaInfo {
|
|
public:
|
|
|
|
mgshortestpathaInfo(graph::Graph* _graph,
|
|
int _startNode, int _endNode, int _resultSelect,
|
|
Word& _arg, Word& _arg2, TupleType* _tt)
|
|
: graph(_graph),startNode(_startNode),
|
|
endNode(_endNode),resultSelect(_resultSelect),
|
|
arg(_arg),arg2(_arg2), tt(_tt),seqNo(1) {
|
|
|
|
result = new ttree::TTree<TupleWrap,TupleComp>(16,18);
|
|
|
|
bool found = shortestPath(graph,startNode,endNode,arg,arg2,true);
|
|
if(found || resultSelect == 3) {
|
|
resultSelection();
|
|
}
|
|
else
|
|
cerr << "no path found" << endl;
|
|
|
|
iterator = result->begin();
|
|
|
|
}
|
|
|
|
~mgshortestpathaInfo() {
|
|
graph->reset();
|
|
delete result;
|
|
result = 0;
|
|
tt->DeleteIfAllowed();
|
|
}
|
|
|
|
Tuple* next() {
|
|
if(iterator.end())
|
|
return 0;
|
|
Tuple* res = (*iterator).getPointer();
|
|
if(res==NULL) {
|
|
return 0;
|
|
}
|
|
iterator++;
|
|
res->IncReference();
|
|
return res;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
~resultSelection~
|
|
|
|
*/
|
|
void resultSelection() {
|
|
|
|
switch(resultSelect) {
|
|
case 0: { // shortest path
|
|
|
|
seqNo = 1;
|
|
int source = startNode;
|
|
int dest = 0;
|
|
|
|
for(size_t i=1; i<graph->getResult()->size(); i++) {
|
|
dest = graph->getResult()->at(i);
|
|
Tuple* tup = graph->getEdge(source,dest);
|
|
if(!tup)
|
|
break;
|
|
appendTuple(tup,tt,seqNo,result);
|
|
seqNo++;
|
|
source = dest;
|
|
}
|
|
graph->reset();
|
|
break;
|
|
}
|
|
case 1: { //Remaining elements in priority queue
|
|
|
|
break;
|
|
}
|
|
|
|
case 2: { //visited sections
|
|
|
|
break;
|
|
}
|
|
|
|
case 3: { //shortest path tree
|
|
|
|
break;
|
|
}
|
|
|
|
default: { //should have never been reached
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
protected:
|
|
|
|
graph::Graph* graph;
|
|
int startNode;
|
|
int endNode;
|
|
int resultSelect;
|
|
Word arg;
|
|
Word arg2;
|
|
TupleType* tt;
|
|
int seqNoAttrIndex;
|
|
int seqNo;
|
|
ttree::TTree<TupleWrap,TupleComp>* result;
|
|
ttree::Iterator<TupleWrap,TupleComp> iterator;
|
|
};
|
|
|
|
|
|
/*
|
|
|
|
7.34.2 Value Mapping Function of operator ~mgshortestpatha~
|
|
|
|
*/
|
|
template<class T>
|
|
int mgshortestpathaValMap (Word* args, Word& result,
|
|
int message, Word& local, Supplier s) {
|
|
|
|
mgshortestpathaInfo* li = (mgshortestpathaInfo*) local.addr;
|
|
|
|
switch (message) {
|
|
case OPEN: {
|
|
|
|
if(li){
|
|
delete li;
|
|
local.addr=0;
|
|
}
|
|
|
|
int resultSelect = ((CcInt*)args[3].addr)->GetIntval();
|
|
if(resultSelect<0 || resultSelect>3) {
|
|
cerr << "Selected result value does not exist. Enter 0 for shortest "
|
|
<< "path, 1 for remaining priority queue elements, 2 for visited "
|
|
<< "edges, 3 for shortest path tree." << endl;
|
|
return 0;
|
|
}
|
|
|
|
// Check for simplest Case
|
|
int startNode = ((CcInt*)args[1].addr)->GetIntval();
|
|
int endNode = ((CcInt*)args[2].addr)->GetIntval();
|
|
if(resultSelect<3) {
|
|
if(startNode == endNode) {
|
|
cerr << "source and target node are equal, no path";
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
T* oN = (T*) args[0].addr;
|
|
|
|
MemoryGraphObject* memgraph = getMemGraph(oN);
|
|
if(!memgraph) {
|
|
return 0;
|
|
}
|
|
|
|
ListExpr tupleType = GetTupleResultType(s);
|
|
TupleType* tt = new TupleType(nl->Second(tupleType));
|
|
|
|
local.addr = new mgshortestpathaInfo(memgraph->getgraph(),
|
|
startNode,
|
|
endNode,
|
|
resultSelect,
|
|
args[4],args[5],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 -1;
|
|
}
|
|
|
|
|
|
ValueMapping mgshortestpathaVM[] = {
|
|
mgshortestpathaValMap<Mem>,
|
|
mgshortestpathaValMap<MPointer>,
|
|
};
|
|
|
|
int mgshortestpathaSelect(ListExpr args){
|
|
return Mem::checkType(nl->First(args))?0:1;
|
|
}
|
|
|
|
|
|
/*
|
|
|
|
7.34.4 Description of operator ~mgshortestpatha~
|
|
|
|
*/
|
|
OperatorSpec mgshortestpathaSpec(
|
|
"MGRAPH x int x int x int x (tuple->real) x "
|
|
"(tuple->real) -> stream(tuple(a1:t1,...an+1:tn+1))",
|
|
"_ mgshortestpatha [_,_,_; fun, fun] implicit parameter tuple type MTUPLE",
|
|
"finds the shortest path between to given nodes in a main memory "
|
|
"graph using the a*-algorithm",
|
|
"query mwrap('graph') mgshortestpatha "
|
|
"[1,40,0; distance(.SourcePos,.TargetPos), "
|
|
"distance(.SourcePos,.TargetPos) * 2.0] count"
|
|
);
|
|
|
|
|
|
/*
|
|
|
|
7.34.5 Instance of operator ~mgshortestpatha~
|
|
|
|
*/
|
|
Operator mgshortestpathaOp (
|
|
"mgshortestpatha",
|
|
mgshortestpathaSpec.getStr(),
|
|
2,
|
|
mgshortestpathaVM,
|
|
mgshortestpathaSelect,
|
|
mgshortestpathdTypeMap<true>
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
7.35 Operator ~mcreatemgraph~ and ~mcreatemgraphflob~
|
|
|
|
The operator ~mcreatemgraph~ creates a main memory graph using adjacency list
|
|
from an ordered relation which represents a graph as well.
|
|
of the main memory graph is successful the operator returns true.
|
|
In addition the operator ~mcreatemgraphflob~ loads the flobs of the attributes
|
|
into the main memory.
|
|
|
|
7.35.1 Type Mapping Functions of operator ~mcreatemgraph~ and
|
|
~mcreatemgraphflob~
|
|
|
|
orel(tuple(x)) -> mpointer(mem(graph(orel)))
|
|
|
|
*/
|
|
ListExpr mcreatemgraphTypeMap(ListExpr args) {
|
|
|
|
if(nl->ListLength(args)!=1){
|
|
return listutils::typeError("wrong number of arguments");
|
|
}
|
|
ListExpr arg = nl->First(args);
|
|
if(!OrderedRelation::checkType(arg)){
|
|
return listutils::typeError("argument is not an ordered relation");
|
|
}
|
|
|
|
// check if tuples contain at least to integer values
|
|
ListExpr orelTuple = nl->Second(arg);
|
|
ListExpr attrlist(nl->Second(orelTuple));
|
|
|
|
ListExpr rest = attrlist;
|
|
bool foundSource = false;
|
|
bool foundTarget = false;
|
|
|
|
if(!nl->HasMinLength(attrlist,2)){
|
|
return listutils::typeError("orel has less than "
|
|
"two integer attributes.");
|
|
|
|
}
|
|
|
|
while(!nl->IsEmpty(rest)) {
|
|
ListExpr listn = nl->OneElemList(nl->Second(nl->First(rest)));
|
|
if(listutils::isSymbol(nl->First(listn),CcInt::BasicType())) {
|
|
if(!foundSource)
|
|
foundSource = true;
|
|
else {
|
|
foundTarget = true;
|
|
break;
|
|
}
|
|
}
|
|
rest = nl->Rest(rest);
|
|
}
|
|
|
|
if(!foundSource || !foundTarget) {
|
|
return listutils::typeError("orel has less than 2 int attributes.");
|
|
}
|
|
|
|
return MPointer::wrapType(Mem::wrapType(
|
|
MemoryGraphObject::wrapType(orelTuple)));
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
|
7.35.2 The Value Mapping Functions of operator ~mcreatemgraph~
|
|
|
|
*/
|
|
template<bool flob>
|
|
int mcreatemgraphValMap(Word* args, Word& result,
|
|
int message, Word& local, Supplier s) {
|
|
result = qp->ResultStorage(s);
|
|
MPointer* mp = static_cast<MPointer*>(result.addr);
|
|
bool mcreatemgraphsucceed = false;
|
|
Supplier t = qp->GetSon( s, 0 );
|
|
ListExpr le = qp->GetType(t);
|
|
GenericRelation* rel = static_cast<GenericRelation*>(args[0].addr);
|
|
MemoryGraphObject* memgraph = new MemoryGraphObject();
|
|
mcreatemgraphsucceed = memgraph->relToGraph(rel,le,getDBname(),flob);
|
|
if(mcreatemgraphsucceed) {
|
|
mp->setPointer(memgraph);
|
|
memgraph->deleteIfAllowed();
|
|
} else {
|
|
memgraph->deleteIfAllowed(); // it managed by the catalog
|
|
mp->setPointer(0);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
|
|
7.35.4 Description of operator ~mcreatemgraph~
|
|
|
|
*/
|
|
OperatorSpec createmgrepahSpec(
|
|
"orel(tuple(x)) -> bool",
|
|
"mcreatemgraph(_)",
|
|
"creates a main memory graph object from an ordered relation",
|
|
"query mcreatemgraph (otestrel)"
|
|
);
|
|
|
|
|
|
/*
|
|
|
|
7.35.5 Instance of operator ~mcreatemgraph~
|
|
|
|
*/
|
|
Operator mcreatemgraphOp (
|
|
"mcreatemgraph",
|
|
createmgrepahSpec.getStr(),
|
|
mcreatemgraphValMap<false>,
|
|
Operator::SimpleSelect,
|
|
mcreatemgraphTypeMap
|
|
);
|
|
|
|
/*
|
|
|
|
7.36.4 Description of operator ~mcreatemgraphflob~
|
|
|
|
*/
|
|
OperatorSpec mcreatemgraphflobSpec(
|
|
"orel(tuple(x)) -> mpointer(mem(graph(tuple(x))))",
|
|
"mcreatemgraphflob (_)",
|
|
"creates a main memory graph object from a given ordered relation "
|
|
"and loads the flobs into the main memory",
|
|
"query mcreatemgraphflob (otestrel)"
|
|
);
|
|
|
|
|
|
/*
|
|
|
|
7.36.5 Instance of operator ~mcreatemgraphflob~
|
|
|
|
*/
|
|
Operator mcreatemgraphflobOp (
|
|
"mcreatemgraphflob",
|
|
mcreatemgraphflobSpec.getStr(),
|
|
mcreatemgraphValMap<true>,
|
|
Operator::SimpleSelect,
|
|
mcreatemgraphTypeMap
|
|
);
|
|
|
|
|
|
/*
|
|
|
|
7.37 Operator ~mgconnectedcomponents~
|
|
|
|
The operator ~mgconnectedcomponents~ computes the strongly connected
|
|
components in a given main meory graph. the tuples of the graph
|
|
with the appended component number are returned in an output stream.
|
|
|
|
7.37.1 Type Mapping Functions of operator ~mgconnectedcomponents~
|
|
|
|
{string, mem(graph(tuple(x)))} -> stream(tuple(a1:t1,...an+1:tn+1))
|
|
|
|
*/
|
|
template<bool perNode>
|
|
ListExpr mgconnectedcomponentsTypeMap(ListExpr args) {
|
|
|
|
if(nl->ListLength(args) != 1) {
|
|
return listutils::typeError("one argument expected");
|
|
}
|
|
ListExpr graph;
|
|
if(!getMemSubType(nl->First(args), graph)){
|
|
return listutils::typeError("argument is not a memory object");
|
|
}
|
|
|
|
if(!MemoryGraphObject::checkType(graph))
|
|
return listutils::typeError("first arg is not a mem graph");
|
|
|
|
// check if second argument attribute of relation
|
|
graph = nl->Second(graph);
|
|
ListExpr relAttrList(nl->Second(graph));
|
|
|
|
if(!listutils::isAttrList(relAttrList)) {
|
|
return listutils::typeError("Error in rel attrlist.");
|
|
}
|
|
|
|
// appends Attribute CompNo to Attributes in orel
|
|
ListExpr rest = nl->Second(graph);
|
|
ListExpr listn = nl->OneElemList(nl->First(rest));
|
|
ListExpr lastlistn = listn;
|
|
rest = nl->Rest(rest);
|
|
while (!(nl->IsEmpty(rest))) {
|
|
lastlistn = nl->Append(lastlistn,nl->First(rest));
|
|
rest = nl->Rest(rest);
|
|
}
|
|
string n1 = perNode?"SourceComp":"CompNo";
|
|
lastlistn = nl->Append(lastlistn,
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom(n1),
|
|
listutils::basicSymbol<CcInt>()));
|
|
if(perNode){
|
|
lastlistn = nl->Append(lastlistn,
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom("TargetComp"),
|
|
listutils::basicSymbol<CcInt>()));
|
|
}
|
|
|
|
|
|
return nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()),
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom(Tuple::BasicType()),
|
|
listn));
|
|
}
|
|
|
|
template<bool iter, bool perNode>
|
|
class mgconnectedComponentsInfo{
|
|
public:
|
|
mgconnectedComponentsInfo(graph::Graph* _graph,
|
|
TupleType* _tt)
|
|
: graph(_graph),tt(_tt) {
|
|
|
|
// compute the strongly connected components
|
|
graph->resetComp();
|
|
|
|
if(iter){
|
|
graph->tarjan2();
|
|
} else {
|
|
graph->tarjan();
|
|
}
|
|
graphit = graph->getGraph()->begin();
|
|
nextVertex();
|
|
}
|
|
|
|
~mgconnectedComponentsInfo(){
|
|
tt->DeleteIfAllowed();
|
|
}
|
|
|
|
|
|
Tuple* next() {
|
|
while(graphit != graph->getGraph()->end()) {
|
|
if(vertexit!=vertex->getEdges()->end()){
|
|
Tuple* result = createResultTuple(
|
|
vertexit->getPointer()->getTuple());
|
|
vertexit++;
|
|
return result;
|
|
}
|
|
graphit++;
|
|
nextVertex();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
private:
|
|
graph::Graph* graph;
|
|
TupleType* tt;
|
|
set<graph::Vertex*,graph::Vertex::EqualVertex>::iterator graphit;
|
|
vector<graph::EdgeWrap>::iterator vertexit;
|
|
int compNo;
|
|
graph::Vertex* vertex;
|
|
|
|
void nextVertex(){
|
|
if(graphit!= graph->getGraph()->end()){
|
|
vertex = *graphit;
|
|
compNo = vertex->getCompNo();
|
|
vertexit = vertex->getEdges()->begin();
|
|
} else {
|
|
vertex = 0;
|
|
compNo = -1;
|
|
}
|
|
}
|
|
|
|
Tuple* createResultTuple(Tuple* tup){
|
|
// copy original attributes
|
|
Tuple* res = new Tuple(tt);
|
|
for(int i=0; i<tup->GetNoAttributes(); i++) {
|
|
res->CopyAttribute(i,tup,i);
|
|
}
|
|
// append new Attributes
|
|
graph::Vertex* w = graph->getVertex(vertexit->getPointer()->getDest());
|
|
if(!perNode){
|
|
int comp = w->getCompNo()==compNo?compNo:-2;
|
|
res->PutAttribute(tup->GetNoAttributes(),new CcInt(true,comp));
|
|
return res;
|
|
}
|
|
res->PutAttribute(tup->GetNoAttributes(),new CcInt(true,compNo));
|
|
res->PutAttribute(tup->GetNoAttributes()+1,
|
|
new CcInt(true,w->getCompNo()));
|
|
return res;
|
|
}
|
|
};
|
|
|
|
/*
|
|
|
|
7.37.2 Value Mapping Function of operator ~mgconnectedcomponents~
|
|
|
|
*/
|
|
template<class T,bool iter, bool perNode>
|
|
int mgconnectedcomponentsValMap (Word* args, Word& result,
|
|
int message, Word& local, Supplier s) {
|
|
|
|
mgconnectedComponentsInfo<iter, perNode>* li =
|
|
(mgconnectedComponentsInfo<iter, perNode>*) local.addr;
|
|
|
|
switch (message) {
|
|
case OPEN: {
|
|
|
|
if(li){
|
|
delete li;
|
|
local.addr=0;
|
|
}
|
|
T* oN = (T*) args[0].addr;
|
|
|
|
|
|
MemoryGraphObject* memgraph = getMemGraph(oN);
|
|
if(!memgraph) {
|
|
return 0;
|
|
}
|
|
|
|
ListExpr tupleType = GetTupleResultType(s);
|
|
TupleType* tt = new TupleType(nl->Second(tupleType));
|
|
|
|
local.addr= new mgconnectedComponentsInfo<iter,perNode>(
|
|
memgraph->getgraph(),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 -1;
|
|
}
|
|
|
|
|
|
ValueMapping mgconnectedcomponentsVM[] = {
|
|
mgconnectedcomponentsValMap<Mem,false, false>,
|
|
mgconnectedcomponentsValMap<MPointer,false, false>,
|
|
};
|
|
|
|
|
|
ValueMapping mgconnectedcomponentsVM2[] = {
|
|
mgconnectedcomponentsValMap<Mem,true, false>,
|
|
mgconnectedcomponentsValMap<MPointer,true, false>,
|
|
};
|
|
|
|
ValueMapping mgconnectedcomponentsVM3[] = {
|
|
mgconnectedcomponentsValMap<Mem,true, true>,
|
|
mgconnectedcomponentsValMap<MPointer,true, true>
|
|
};
|
|
|
|
|
|
int mgconnectedcomponentsSelect(ListExpr args){
|
|
return Mem::checkType(nl->First(args))?0:1;
|
|
}
|
|
|
|
|
|
/*
|
|
|
|
7.37.4 Description of operator ~mgconnectedcomponents~
|
|
|
|
*/
|
|
OperatorSpec mgconnectedcomponentsSpec(
|
|
"MGRAPH -> stream(Tuple)",
|
|
"_ mgconnectedcomponents",
|
|
"computes the scc's for a given main memory graph",
|
|
"query graph mgconnectedcomponents"
|
|
);
|
|
|
|
/*
|
|
|
|
7.37.5 Instance of operator ~mgconnectedcomponents~
|
|
|
|
*/
|
|
Operator mgconnectedcomponents_oldOp (
|
|
"mgconnectedcomponents_old",
|
|
mgconnectedcomponentsSpec.getStr(),
|
|
2,
|
|
mgconnectedcomponentsVM,
|
|
mgconnectedcomponentsSelect,
|
|
mgconnectedcomponentsTypeMap<false>
|
|
);
|
|
|
|
Operator mgconnectedcomponentsOp (
|
|
"mgconnectedcomponents",
|
|
mgconnectedcomponentsSpec.getStr(),
|
|
2,
|
|
mgconnectedcomponentsVM2,
|
|
mgconnectedcomponentsSelect,
|
|
mgconnectedcomponentsTypeMap<false>
|
|
);
|
|
|
|
|
|
Operator mgconnectedcomponentsNOp (
|
|
"mgconnectedcomponentsN",
|
|
mgconnectedcomponentsSpec.getStr(),
|
|
2,
|
|
mgconnectedcomponentsVM3,
|
|
mgconnectedcomponentsSelect,
|
|
mgconnectedcomponentsTypeMap<true>
|
|
);
|
|
|
|
/*
|
|
7.38 ~momapmatchmht~
|
|
|
|
7.38.1 Operator-Info
|
|
map matching with a main memory ordered relation
|
|
Result: Tuples of matched edges with timestamps
|
|
|
|
*/
|
|
// struct MOMapMatchMHTInfo : OperatorInfo {
|
|
// MOMapMatchMHTInfo() {
|
|
// name = "momapmatchmht";
|
|
// signature = MemoryORelObject::BasicType() + " x " +
|
|
// rtreehelper::BasicType() + " x " +
|
|
// MemoryRelObject::BasicType() + " x " +
|
|
// temporalalgebra::MPoint::BasicType() + " -> " +
|
|
// "stream(tuple([<attributes of tuple of edge>,"
|
|
// "StartTime:DateTime, EndTime:DateTime]))";
|
|
//
|
|
// appendSignature(MemoryORelObject::BasicType() + " x " +
|
|
// rtreehelper::BasicType() + " x " +
|
|
// MemoryRelObject::BasicType() + " x " +
|
|
// FText::BasicType() + " -> " +
|
|
// "stream(tuple([<attributes of tuple of edge>,"
|
|
// "StartTime:DateTime, EndTime:DateTime]))");
|
|
//
|
|
// appendSignature(MemoryORelObject::BasicType() + " x " +
|
|
// rtreehelper::BasicType() + " x " +
|
|
// MemoryRelObject::BasicType() + " x " +
|
|
// "(stream (tuple([Lat:real, Lon:real, Time:DateTime "
|
|
// "[,Fix:int] [,Sat:int] [,Hdop : real]"
|
|
// "[,Vdop:real] [,Pdop:real] "
|
|
// "[,Course:real] [,Speed(m/s):real]])))"
|
|
// + " -> " +
|
|
// "stream(tuple([<attributes of tuple of edge>,"
|
|
// "StartTime:DateTime, EndTime:DateTime]))");
|
|
//
|
|
//
|
|
// syntax = "momapmatchmht ( _ , _ , _ , _ )";
|
|
// meaning = "The operation maps the MPoint or "
|
|
// "the data of a gpx-file or "
|
|
// "the data of a tuple stream "
|
|
// "to the given network, which is based on a "
|
|
// "main memory ordered relation."
|
|
// "Result is a stream of tuples with the matched edges "
|
|
// "of the network with timestamps.";
|
|
// example = "momapmatchmht('Edges', 'EdgeIndex_Box_rtree', "
|
|
// "'EdgeIndex', 'Trk_Dortmund.gpx')";
|
|
// }
|
|
// };
|
|
|
|
|
|
// static ListExpr GetORelNetworkAttrIndexes(ListExpr ORelAttrList);
|
|
|
|
|
|
// static ListExpr GetMMDataIndexesOfTupleStream(ListExpr TupleStream);
|
|
|
|
|
|
// enum MOMapMatchingMHTResultType {
|
|
// OMM_RESULT_STREAM,
|
|
// OMM_RESULT_GPX,
|
|
// OMM_RESULT_MPOINT
|
|
// };
|
|
|
|
|
|
// static ListExpr AppendLists(ListExpr List1, ListExpr List2) {
|
|
//
|
|
// ListExpr ResultList = nl->TheEmptyList();
|
|
// ListExpr last = nl->TheEmptyList();
|
|
//
|
|
// ListExpr Lauf = List1;
|
|
//
|
|
// while (!nl->IsEmpty(Lauf)) {
|
|
// ListExpr attr = nl->First(Lauf);
|
|
//
|
|
// if (nl->IsEmpty(ResultList)) {
|
|
// ResultList = nl->OneElemList(attr);
|
|
// last = ResultList;
|
|
// }
|
|
// else
|
|
// last = nl->Append(last, attr);
|
|
//
|
|
// Lauf = nl->Rest(Lauf);
|
|
// }
|
|
//
|
|
// Lauf = List2;
|
|
//
|
|
// while (!nl->IsEmpty(Lauf)) {
|
|
// ListExpr attr = nl->First(Lauf);
|
|
//
|
|
// if (nl->IsEmpty(ResultList)) {
|
|
// ResultList = nl->OneElemList(attr);
|
|
// last = ResultList;
|
|
// }
|
|
// else
|
|
// last = nl->Append(last, attr);
|
|
//
|
|
// Lauf = nl->Rest(Lauf);
|
|
// }
|
|
//
|
|
// return ResultList;
|
|
// }
|
|
|
|
|
|
// template<class T>
|
|
// static typename mapmatching::MmORelNetwork<T>::OEdgeAttrIndexes
|
|
// GetOEdgeAttrIndexes(Word* args, int nOffset) {
|
|
// // s. GetORelNetworkAttrIndexes
|
|
//
|
|
// typename mapmatching::MmORelNetwork<T>::OEdgeAttrIndexes Indexes;
|
|
//
|
|
// const CcInt* pIdxSource = static_cast<CcInt*>(args[nOffset + 0].addr);
|
|
// const CcInt* pIdxTarget = static_cast<CcInt*>(args[nOffset + 1].addr);
|
|
// const CcInt* pIdxSourcePos = static_cast<CcInt*>(args[nOffset + 2].addr);
|
|
// const CcInt* pIdxTargetPos = static_cast<CcInt*>(args[nOffset + 3].addr);
|
|
// const CcInt* pIdxCurve = static_cast<CcInt*>(args[nOffset + 4].addr);
|
|
// const CcInt* pIdxRoadName = static_cast<CcInt*>(args[nOffset + 5].addr);
|
|
// const CcInt* pIdxRoadType = static_cast<CcInt*>(args[nOffset + 6].addr);
|
|
// const CcInt* pIdxMaxSpeed = static_cast<CcInt*>(args[nOffset + 7].addr);
|
|
// const CcInt* pIdxWayId = static_cast<CcInt*>(args[nOffset + 8].addr);
|
|
//
|
|
//
|
|
// Indexes.m_IdxSource = pIdxSource->GetValue();
|
|
// Indexes.m_IdxTarget = pIdxTarget->GetValue();
|
|
// Indexes.m_IdxSourcePos = pIdxSourcePos->GetValue();
|
|
// Indexes.m_IdxTargetPos = pIdxTargetPos->GetValue();
|
|
// Indexes.m_IdxCurve = pIdxCurve->GetValue();
|
|
// Indexes.m_IdxRoadName = pIdxRoadName->GetValue();
|
|
// Indexes.m_IdxRoadType = pIdxRoadType->GetValue();
|
|
// Indexes.m_IdxMaxSpeed = pIdxMaxSpeed->GetValue();
|
|
// Indexes.m_IdxWayId = pIdxWayId->GetValue();
|
|
//
|
|
// if (Indexes.m_IdxSource < 0 || Indexes.m_IdxTarget < 0 ||
|
|
// Indexes.m_IdxSourcePos < 0 || Indexes.m_IdxTargetPos < 0 ||
|
|
// Indexes.m_IdxCurve < 0 || Indexes.m_IdxWayId < 0)
|
|
// {
|
|
// assert(false);
|
|
// }
|
|
//
|
|
// return Indexes;
|
|
// }
|
|
|
|
|
|
// static ListExpr GetORelNetworkAttrIndexes(ListExpr ORelAttrList) {
|
|
// ListExpr attrType;
|
|
// int nAttrSourceIndex =
|
|
// listutils::findAttribute(ORelAttrList, "Source", attrType);
|
|
// if (nAttrSourceIndex == 0)
|
|
// return listutils::typeError("'Source' not found in attr list");
|
|
// else {
|
|
// if (!CcInt::checkType(attrType) &&
|
|
// !LongInt::checkType(attrType)) {
|
|
// return listutils::typeError(
|
|
// "'Source' must be " + CcInt::BasicType() +
|
|
// " or " + LongInt::BasicType());
|
|
// }
|
|
// }
|
|
//
|
|
// int nAttrTargetIndex =
|
|
// listutils::findAttribute(ORelAttrList, "Target", attrType);
|
|
// if (nAttrTargetIndex == 0) {
|
|
// return listutils::typeError("'Target' not found in attr list");
|
|
// }
|
|
// else {
|
|
// if (!CcInt::checkType(attrType) &&
|
|
// !LongInt::checkType(attrType)) {
|
|
// return listutils::typeError(
|
|
// "'Target' must be " + CcInt::BasicType()
|
|
// + " or " + LongInt::BasicType()) ;
|
|
// }
|
|
// }
|
|
//
|
|
// int nAttrSourcePosIndex = listutils::findAttribute(
|
|
// ORelAttrList, "SourcePos", attrType);
|
|
// if (nAttrSourcePosIndex == 0) {
|
|
// return listutils::typeError("'SourcePos' not found in attr list");
|
|
// }
|
|
// else {
|
|
// if (!listutils::isSymbol(attrType, Point::BasicType())) {
|
|
// return listutils::typeError(
|
|
// "'SourcePos' must be " + Point::BasicType());
|
|
// }
|
|
// }
|
|
//
|
|
// int nAttrTargetPosIndex = listutils::findAttribute(
|
|
// ORelAttrList, "TargetPos", attrType);
|
|
// if (nAttrTargetPosIndex == 0) {
|
|
// return listutils::typeError("'TargetPos' not found in attr list");
|
|
// }
|
|
// else {
|
|
// if (!listutils::isSymbol(attrType, Point::BasicType())) {
|
|
// return listutils::typeError(
|
|
// "'TargetPos' must be " + Point::BasicType());
|
|
// }
|
|
// }
|
|
//
|
|
// int nAttrCurveIndex = listutils::findAttribute(
|
|
// ORelAttrList, "Curve", attrType);
|
|
// if (nAttrCurveIndex == 0) {
|
|
// return listutils::typeError("'Curve' not found in attr list");
|
|
// }
|
|
// else {
|
|
// if (!listutils::isSymbol(attrType, SimpleLine::BasicType())) {
|
|
// return listutils::typeError(
|
|
// "'Curve' must be " + SimpleLine::BasicType());
|
|
// }
|
|
// }
|
|
//
|
|
// int nAttrRoadNameIndex = listutils::findAttribute(
|
|
// ORelAttrList, "RoadName", attrType);
|
|
// if (nAttrRoadNameIndex != 0)
|
|
// {
|
|
// if (!listutils::isSymbol(attrType, FText::BasicType()))
|
|
// {
|
|
// return listutils::typeError(
|
|
// "'RoadName' must be " + FText::BasicType());
|
|
// }
|
|
// }
|
|
//
|
|
// int nAttrRoadTypeIndex = listutils::findAttribute(
|
|
// ORelAttrList, "RoadType", attrType);
|
|
// if (nAttrRoadTypeIndex != 0)
|
|
// {
|
|
// if (!listutils::isSymbol(attrType, FText::BasicType()))
|
|
// {
|
|
// return listutils::typeError(
|
|
// "'RoadType' must be " + FText::BasicType());
|
|
// }
|
|
// }
|
|
//
|
|
// int nAttrMaxSpeedTypeIndex = listutils::findAttribute(
|
|
// ORelAttrList, "MaxSpeed", attrType);
|
|
// if (nAttrMaxSpeedTypeIndex != 0)
|
|
// {
|
|
// if (!listutils::isSymbol(attrType, FText::BasicType()))
|
|
// {
|
|
// return listutils::typeError(
|
|
// "'MaxSpeed' must be " + FText::BasicType());
|
|
// }
|
|
// }
|
|
//
|
|
// int nAttrWayIdTypeIndex = listutils::findAttribute(
|
|
// ORelAttrList, "WayId", attrType);
|
|
// if (nAttrWayIdTypeIndex == 0)
|
|
// {
|
|
// return listutils::typeError("'WayId' not found in attr list");
|
|
// }
|
|
// else
|
|
// {
|
|
// if (!CcInt::checkType(attrType) &&
|
|
// !LongInt::checkType(attrType))
|
|
// {
|
|
// return listutils::typeError(
|
|
// "'WayId' must be " + CcInt::BasicType()
|
|
// + " or " + LongInt::BasicType());
|
|
// }
|
|
// }
|
|
//
|
|
// --nAttrSourceIndex;
|
|
// --nAttrTargetIndex;
|
|
// --nAttrSourcePosIndex;
|
|
// --nAttrTargetPosIndex;
|
|
// --nAttrCurveIndex;
|
|
// --nAttrRoadNameIndex;
|
|
// --nAttrRoadTypeIndex;
|
|
// --nAttrMaxSpeedTypeIndex;
|
|
// --nAttrWayIdTypeIndex;
|
|
//
|
|
// ListExpr Ind = nl->OneElemList(nl->IntAtom(nAttrSourceIndex));
|
|
// ListExpr Last = Ind;
|
|
// Last = nl->Append(Last, nl->IntAtom(nAttrTargetIndex));
|
|
// Last = nl->Append(Last, nl->IntAtom(nAttrSourcePosIndex));
|
|
// Last = nl->Append(Last, nl->IntAtom(nAttrTargetPosIndex));
|
|
// Last = nl->Append(Last, nl->IntAtom(nAttrCurveIndex));
|
|
// Last = nl->Append(Last, nl->IntAtom(nAttrRoadNameIndex));
|
|
// Last = nl->Append(Last, nl->IntAtom(nAttrRoadTypeIndex));
|
|
// Last = nl->Append(Last, nl->IntAtom(nAttrMaxSpeedTypeIndex));
|
|
// Last = nl->Append(Last, nl->IntAtom(nAttrWayIdTypeIndex));
|
|
//
|
|
// return Ind;
|
|
// }
|
|
|
|
|
|
// static shared_ptr<mapmatch::MapMatchDataContainer>
|
|
// GetMMDataFromTupleStream(Supplier Stream,
|
|
// Word* args,
|
|
// int nOffset) {
|
|
//
|
|
// shared_ptr<mapmatch::MapMatchDataContainer>
|
|
// pContData(new mapmatch::MapMatchDataContainer);
|
|
//
|
|
// const CcInt* pIdxLat = static_cast<CcInt*>(args[nOffset + 0].addr);
|
|
// const CcInt* pIdxLon = static_cast<CcInt*>(args[nOffset + 1].addr);
|
|
// const CcInt* pIdxTime = static_cast<CcInt*>(args[nOffset + 2].addr);
|
|
// const CcInt* pIdxFix = static_cast<CcInt*>(args[nOffset + 3].addr);
|
|
// const CcInt* pIdxSat = static_cast<CcInt*>(args[nOffset + 4].addr);
|
|
// const CcInt* pIdxHdop = static_cast<CcInt*>(args[nOffset + 5].addr);
|
|
// const CcInt* pIdxVdop = static_cast<CcInt*>(args[nOffset + 6].addr);
|
|
// const CcInt* pIdxPdop = static_cast<CcInt*>(args[nOffset + 7].addr);
|
|
// const CcInt* pIdxCourse = static_cast<CcInt*>(args[nOffset + 8].addr);
|
|
// const CcInt* pIdxSpeed = static_cast<CcInt*>(args[nOffset + 9].addr);
|
|
// //const CcInt* pIdxEle = static_cast<CcInt*>(args[nOffset + 10].addr);
|
|
//
|
|
// const int nIdxLat = pIdxLat->GetValue();
|
|
// const int nIdxLon = pIdxLon->GetValue();
|
|
// const int nIdxTime = pIdxTime->GetValue();
|
|
// const int nIdxFix = pIdxFix->GetValue();
|
|
// const int nIdxSat = pIdxSat->GetValue();
|
|
// const int nIdxHdop = pIdxHdop->GetValue();
|
|
// const int nIdxVdop = pIdxVdop->GetValue();
|
|
// const int nIdxPdop = pIdxPdop->GetValue();
|
|
// const int nIdxCourse = pIdxCourse->GetValue();
|
|
// const int nIdxSpeed = pIdxSpeed->GetValue();
|
|
// //const int nIdxEle = pIdxEle->GetValue();
|
|
//
|
|
// if (nIdxLat < 0 || nIdxLon < 0 || nIdxTime < 0) {
|
|
// assert(false);
|
|
// return pContData;
|
|
// }
|
|
//
|
|
// Word wTuple;
|
|
// qp->Open(Stream);
|
|
// qp->Request(Stream, wTuple);
|
|
// while (qp->Received(Stream)) {
|
|
// Tuple* pTpl = (Tuple*)wTuple.addr;
|
|
//
|
|
// CcReal* pLat = static_cast<CcReal*>(pTpl->GetAttribute(nIdxLat));
|
|
// CcReal* pLon = static_cast<CcReal*>(pTpl->GetAttribute(nIdxLon));
|
|
// DateTime* pTime =
|
|
// static_cast<DateTime*>(pTpl->GetAttribute(nIdxTime));
|
|
//
|
|
// CcInt* pFix = NULL;
|
|
// if (nIdxFix >= 0)
|
|
// pFix = static_cast<CcInt*>(pTpl->GetAttribute(nIdxFix));
|
|
//
|
|
// CcInt* pSat = NULL;
|
|
// if (nIdxSat >= 0)
|
|
// pSat = static_cast<CcInt*>(pTpl->GetAttribute(nIdxSat));
|
|
//
|
|
// CcReal* pHdop = NULL;
|
|
// if (nIdxHdop >= 0)
|
|
// pHdop = static_cast<CcReal*>(pTpl->GetAttribute(nIdxHdop));
|
|
//
|
|
// CcReal* pVdop = NULL;
|
|
// if (nIdxVdop >= 0)
|
|
// pVdop = static_cast<CcReal*>(pTpl->GetAttribute(nIdxVdop));
|
|
//
|
|
// CcReal* pPdop = NULL;
|
|
// if (nIdxPdop >= 0)
|
|
// pPdop = static_cast<CcReal*>(pTpl->GetAttribute(nIdxPdop));
|
|
//
|
|
// CcReal* pCourse = NULL;
|
|
// if (nIdxCourse >= 0)
|
|
// pCourse = static_cast<CcReal*>(pTpl->GetAttribute(nIdxCourse));
|
|
//
|
|
// CcReal* pSpeed = NULL;
|
|
// if (nIdxSpeed >= 0)
|
|
// pSpeed = static_cast<CcReal*>(pTpl->GetAttribute(nIdxSpeed));
|
|
//
|
|
// if (pLat != NULL && pLon != NULL && pTime != NULL &&
|
|
// pLat->IsDefined() && pLon->IsDefined() && pTime->IsDefined()) {
|
|
// //cout << "found valid data point" << endl;
|
|
// mapmatch::MapMatchData Data(pLat->GetValue(),
|
|
// pLon->GetValue(),
|
|
// pTime->millisecondsToNull());
|
|
//
|
|
// if (pFix != NULL && pFix->IsDefined())
|
|
// Data.m_nFix = pFix->GetValue();
|
|
//
|
|
// if (pSat != NULL && pSat->IsDefined())
|
|
// Data.m_nSat = pSat->GetValue();
|
|
//
|
|
// if (pHdop != NULL && pHdop->IsDefined())
|
|
// Data.m_dHdop = pHdop->GetValue();
|
|
//
|
|
// if (pVdop != NULL && pVdop->IsDefined())
|
|
// Data.m_dVdop = pVdop->GetValue();
|
|
//
|
|
// if (pPdop != NULL && pPdop->IsDefined())
|
|
// Data.m_dPdop = pPdop->GetValue();
|
|
//
|
|
// if (pCourse != NULL && pCourse->IsDefined())
|
|
// Data.m_dCourse = pCourse->GetValue();
|
|
//
|
|
// if (pSpeed != NULL && pSpeed->IsDefined())
|
|
// Data.m_dSpeed = pSpeed->GetValue();
|
|
//
|
|
// pContData->Append(Data);
|
|
// }
|
|
//
|
|
// pTpl->DeleteIfAllowed();
|
|
// pTpl = NULL;
|
|
//
|
|
// qp->Request(Stream, wTuple);
|
|
// }
|
|
// qp->Close(Stream);
|
|
//
|
|
// return pContData;
|
|
// }
|
|
|
|
|
|
// static ListExpr GetMMDataIndexesOfTupleStream(ListExpr TupleStream) {
|
|
// ListExpr attrType;
|
|
// int nAttrLatIndex = listutils::findAttribute(
|
|
// nl->Second(nl->Second(TupleStream)), "Lat", attrType);
|
|
// if(nAttrLatIndex==0)
|
|
// {
|
|
// return listutils::typeError("'Lat' not found in attr list");
|
|
// }
|
|
// else
|
|
// {
|
|
// if (!listutils::isSymbol(attrType, CcReal::BasicType()))
|
|
// {
|
|
// return listutils::typeError("'Lat' must be " +
|
|
// CcReal::BasicType());
|
|
// }
|
|
// }
|
|
//
|
|
// int nAttrLonIndex = listutils::findAttribute(
|
|
// nl->Second(nl->Second(TupleStream)), "Lon", attrType);
|
|
// if (nAttrLonIndex == 0)
|
|
// {
|
|
// return listutils::typeError("'Lon' not found in attr list");
|
|
// }
|
|
// else
|
|
// {
|
|
// if (!listutils::isSymbol(attrType, CcReal::BasicType()))
|
|
// {
|
|
// return listutils::typeError("'Lon' must be " +
|
|
// CcReal::BasicType());
|
|
// }
|
|
// }
|
|
//
|
|
// int nAttrTimeIndex = listutils::findAttribute(
|
|
// nl->Second(nl->Second(TupleStream)), "Time", attrType);
|
|
// if (nAttrTimeIndex == 0)
|
|
// {
|
|
// return listutils::typeError("'Time' not found in attr list");
|
|
// }
|
|
// else
|
|
// {
|
|
// if (!listutils::isSymbol(attrType, DateTime::BasicType()))
|
|
// {
|
|
// return listutils::typeError("'Time' must be " +
|
|
// DateTime::BasicType());
|
|
// }
|
|
// }
|
|
//
|
|
// int nAttrFixIndex = listutils::findAttribute(
|
|
// nl->Second(nl->Second(TupleStream)), "Fix", attrType);
|
|
// if (nAttrFixIndex != 0)
|
|
// {
|
|
// if (!listutils::isSymbol(attrType, CcInt::BasicType()))
|
|
// {
|
|
// return listutils::typeError("'Fix' must be " +
|
|
// CcInt::BasicType());
|
|
// }
|
|
// }
|
|
//
|
|
// int nAttrSatIndex = listutils::findAttribute(
|
|
// nl->Second(nl->Second(TupleStream)), "Sat", attrType);
|
|
// if (nAttrSatIndex != 0)
|
|
// {
|
|
// if (!listutils::isSymbol(attrType, CcInt::BasicType()))
|
|
// {
|
|
// return listutils::typeError("'Sat' must be " +
|
|
// CcInt::BasicType());
|
|
// }
|
|
// }
|
|
//
|
|
// int nAttrHdopIndex = listutils::findAttribute(
|
|
// nl->Second(nl->Second(TupleStream)), "Hdop", attrType);
|
|
// if (nAttrHdopIndex != 0)
|
|
// {
|
|
// if (!listutils::isSymbol(attrType, CcReal::BasicType()))
|
|
// {
|
|
// return listutils::typeError("'Hdop' must be " +
|
|
// CcReal::BasicType());
|
|
// }
|
|
// }
|
|
//
|
|
// int nAttrVdopIndex = listutils::findAttribute(
|
|
// nl->Second(nl->Second(TupleStream)), "Vdop", attrType);
|
|
// if (nAttrVdopIndex != 0)
|
|
// {
|
|
// if (!listutils::isSymbol(attrType, CcReal::BasicType()))
|
|
// {
|
|
// return listutils::typeError("'Vdop' must be " +
|
|
// CcReal::BasicType());
|
|
// }
|
|
// }
|
|
//
|
|
// int nAttrPdopIndex = listutils::findAttribute(
|
|
// nl->Second(nl->Second(TupleStream)), "Pdop", attrType);
|
|
// if (nAttrPdopIndex != 0)
|
|
// {
|
|
// if (!listutils::isSymbol(attrType, CcReal::BasicType()))
|
|
// {
|
|
// return listutils::typeError("'Pdop' must be " +
|
|
// CcReal::BasicType());
|
|
// }
|
|
// }
|
|
//
|
|
// int nAttrCourseIndex = listutils::findAttribute(
|
|
// nl->Second(nl->Second(TupleStream)), "Course", attrType);
|
|
// if (nAttrCourseIndex != 0)
|
|
// {
|
|
// if (!listutils::isSymbol(attrType, CcReal::BasicType()))
|
|
// {
|
|
// return listutils::typeError(
|
|
// "'Course' must be " + CcReal::BasicType());
|
|
// }
|
|
// }
|
|
//
|
|
// int nAttrSpeedIndex = listutils::findAttribute(
|
|
// nl->Second(nl->Second(TupleStream)), "Speed", attrType);
|
|
// if (nAttrSpeedIndex != 0)
|
|
// {
|
|
// if (!listutils::isSymbol(attrType, CcReal::BasicType()))
|
|
// {
|
|
// return listutils::typeError(
|
|
// "'Speed' must be " + CcReal::BasicType());
|
|
// }
|
|
// }
|
|
//
|
|
// int nAttrEleIndex = listutils::findAttribute(
|
|
// nl->Second(nl->Second(TupleStream)), "Ele", attrType);
|
|
// if (nAttrEleIndex != 0)
|
|
// {
|
|
// if (!listutils::isSymbol(attrType, CcReal::BasicType()))
|
|
// {
|
|
// return listutils::typeError(
|
|
// "'Ele' must be " + CcReal::BasicType());
|
|
// }
|
|
// }
|
|
//
|
|
// --nAttrLatIndex;
|
|
// --nAttrLonIndex;
|
|
// --nAttrTimeIndex;
|
|
// --nAttrFixIndex;
|
|
// --nAttrSatIndex;
|
|
// --nAttrHdopIndex;
|
|
// --nAttrVdopIndex;
|
|
// --nAttrPdopIndex;
|
|
// --nAttrCourseIndex;
|
|
// --nAttrSpeedIndex;
|
|
// --nAttrEleIndex;
|
|
//
|
|
// ListExpr Ind = nl->OneElemList(nl->IntAtom(nAttrLatIndex));
|
|
// ListExpr Last = Ind;
|
|
// Last = nl->Append(Last, nl->IntAtom(nAttrLonIndex));
|
|
// Last = nl->Append(Last, nl->IntAtom(nAttrTimeIndex));
|
|
// Last = nl->Append(Last, nl->IntAtom(nAttrFixIndex));
|
|
// Last = nl->Append(Last, nl->IntAtom(nAttrSatIndex));
|
|
// Last = nl->Append(Last, nl->IntAtom(nAttrHdopIndex));
|
|
// Last = nl->Append(Last, nl->IntAtom(nAttrVdopIndex));
|
|
// Last = nl->Append(Last, nl->IntAtom(nAttrPdopIndex));
|
|
// Last = nl->Append(Last, nl->IntAtom(nAttrCourseIndex));
|
|
// Last = nl->Append(Last, nl->IntAtom(nAttrSpeedIndex));
|
|
// Last = nl->Append(Last, nl->IntAtom(nAttrEleIndex));
|
|
//
|
|
// return Ind;
|
|
// }
|
|
|
|
|
|
/*
|
|
|
|
7.38.2 General Type Mapping for Operators ~momapmatchmht~
|
|
|
|
*/
|
|
// ListExpr momapmatchmhtTypeMap_Common(ListExpr args,
|
|
// MOMapMatchingMHTResultType eResultType) {
|
|
//
|
|
// if(nl->ListLength(args) != 4) {
|
|
// return listutils::typeError("four arguments expected");
|
|
// }
|
|
//
|
|
// // Check Network - OrderedRelation, RTree, Relation
|
|
//
|
|
// // mem(orel)
|
|
// ListExpr arg1 = nl->First(args);
|
|
//
|
|
// if(!nl->HasLength(arg1,2)){
|
|
// return listutils::typeError("internal error");
|
|
// }
|
|
//
|
|
// string errMsg;
|
|
//
|
|
// if(!getMemType(nl->First(arg1), nl->Second(arg1), arg1, errMsg)){
|
|
// return listutils::typeError("string or mem(orel) expected : "
|
|
// + errMsg);
|
|
// }
|
|
//
|
|
// arg1 = nl->Second(arg1); // remove mem
|
|
// if(!listutils::isOrelDescription(arg1)){
|
|
// return listutils::typeError("memory object is not an ordered relation");
|
|
// }
|
|
//
|
|
// ListExpr orelTuple = nl->Second(arg1);
|
|
// if (!listutils::isTupleDescription(orelTuple))
|
|
// {
|
|
// return listutils::typeError
|
|
// ("2nd value of mem orel is not of type tuple");
|
|
// }
|
|
//
|
|
// ListExpr orelAttrList = nl->Second(orelTuple);
|
|
// if (!listutils::isAttrList(orelAttrList)) {
|
|
// return listutils::typeError("Error in orel attrlist");
|
|
// }
|
|
//
|
|
// // Check attributes of orel
|
|
// ListExpr IndNetwAttr = GetORelNetworkAttrIndexes(orelAttrList);
|
|
//
|
|
// if(nl->Equal(IndNetwAttr, nl->TypeError()))
|
|
// return IndNetwAttr;
|
|
//
|
|
// // mem(rtree 2)
|
|
// ListExpr arg2 = nl->Second(args);
|
|
// if(!getMemType(nl->First(arg2), nl->Second(arg2), arg2, errMsg)){
|
|
// return listutils::typeError("\n problem in second arg: " + errMsg);
|
|
// }
|
|
//
|
|
// ListExpr rtreetype = nl->Second(arg2); // remove leading mem
|
|
// if(!rtreehelper::checkType(rtreetype)){
|
|
// return listutils::typeError("second arg is not a mem rtree");
|
|
// }
|
|
//
|
|
// int rtreedim = nl->IntValue(nl->Second(rtreetype));
|
|
//
|
|
// if (rtreedim != 2) {
|
|
// return listutils::typeError("rtree with dim==2 expected");
|
|
// }
|
|
//
|
|
// // mem(rel)
|
|
// ListExpr arg3 = nl->Third(args);
|
|
//
|
|
// if(!nl->HasLength(arg3,2)){
|
|
// return listutils::typeError("internal error");
|
|
// }
|
|
//
|
|
// if(!getMemType(nl->First(arg3), nl->Second(arg3), arg3, errMsg)){
|
|
// return listutils::typeError("string or mem(rel) expected : " + errMsg);
|
|
// }
|
|
//
|
|
// arg3 = nl->Second(arg3); // remove mem
|
|
// if(!Relation::checkType(arg3)){
|
|
// return listutils::typeError("memory object is not a relation");
|
|
// }
|
|
//
|
|
// // GPS-Data (MPoint, FileName, TupleStream)
|
|
// ListExpr arg4 = nl->First(nl->Fourth(args));
|
|
// if (!listutils::isSymbol(arg4,temporalalgebra::MPoint::BasicType()) &&
|
|
// !listutils::isSymbol(arg4,FText::BasicType()) &&
|
|
// !listutils::isTupleStream(arg4)) {
|
|
//
|
|
// return listutils::typeError("4th argument must be " +
|
|
// temporalalgebra::MPoint::BasicType()
|
|
// + " or " +
|
|
// FText::BasicType() + " or " +
|
|
// "tuple stream");
|
|
// }
|
|
//
|
|
// // Result
|
|
// ListExpr ResultType = nl->TheEmptyList();
|
|
//
|
|
// switch (eResultType) {
|
|
// case OMM_RESULT_STREAM: {
|
|
// ListExpr addAttrs = nl->TwoElemList(
|
|
// nl->TwoElemList(nl->SymbolAtom("StartTime"),
|
|
// nl->SymbolAtom(DateTime::BasicType())),
|
|
// nl->TwoElemList(nl->SymbolAtom("EndTime"),
|
|
// nl->SymbolAtom(DateTime::BasicType())));
|
|
//
|
|
// ListExpr ResAttr = AppendLists(orelAttrList, addAttrs);
|
|
//
|
|
// ResultType = nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()),
|
|
// nl->TwoElemList(
|
|
// nl->SymbolAtom(Tuple::BasicType()),
|
|
// ResAttr));
|
|
// }
|
|
// break;
|
|
//
|
|
// case OMM_RESULT_GPX: {
|
|
// ListExpr addAttrs = nl->SixElemList(
|
|
// nl->TwoElemList(nl->SymbolAtom("StartTime"),
|
|
// nl->SymbolAtom(DateTime::BasicType())),
|
|
// nl->TwoElemList(nl->SymbolAtom("EndTime"),
|
|
// nl->SymbolAtom(DateTime::BasicType())),
|
|
// nl->TwoElemList(nl->SymbolAtom("StartPos"),
|
|
// nl->SymbolAtom(Point::BasicType())),
|
|
// nl->TwoElemList(nl->SymbolAtom("EndPos"),
|
|
// nl->SymbolAtom(Point::BasicType())),
|
|
// nl->TwoElemList(nl->SymbolAtom("StartLength"),
|
|
// nl->SymbolAtom(CcReal::BasicType())),
|
|
// nl->TwoElemList(nl->SymbolAtom("EndLength"),
|
|
// nl->SymbolAtom(CcReal::BasicType())));
|
|
//
|
|
// ListExpr ResAttr = AppendLists(orelAttrList, addAttrs);
|
|
//
|
|
// ResultType = nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()),
|
|
// nl->TwoElemList(
|
|
// nl->SymbolAtom(Tuple::BasicType()),
|
|
// ResAttr));
|
|
// }
|
|
// break;
|
|
//
|
|
// case OMM_RESULT_MPOINT: {
|
|
// ResultType = nl->SymbolAtom(temporalalgebra::MPoint::BasicType());
|
|
// }
|
|
// break;
|
|
// }
|
|
//
|
|
//
|
|
// if (listutils::isTupleStream(arg4)) {
|
|
// ListExpr IndMMData = GetMMDataIndexesOfTupleStream(arg4);
|
|
//
|
|
// if (nl->Equal(IndMMData, nl->TypeError()))
|
|
// return IndMMData;
|
|
// else {
|
|
// return nl->ThreeElemList(nl->SymbolAtom(Symbol::APPEND()),
|
|
// AppendLists(IndNetwAttr, IndMMData),
|
|
// ResultType);
|
|
// }
|
|
// }
|
|
// else {
|
|
// return nl->ThreeElemList(nl->SymbolAtom(Symbol::APPEND()),
|
|
// IndNetwAttr,
|
|
// ResultType);
|
|
// }
|
|
// }
|
|
|
|
|
|
// ListExpr momapmatchmhtTypeMap(ListExpr in_xArgs) {
|
|
// return momapmatchmhtTypeMap_Common(in_xArgs, OMM_RESULT_STREAM);
|
|
// }
|
|
|
|
/*
|
|
|
|
7.38.3 Value Mapping Function of operator ~momapmatchmht~
|
|
|
|
*/
|
|
// template<class T, class R, class Q>
|
|
// int momapmatchmhtMPointValueMap(Word* args,
|
|
// Word& result,
|
|
// int message,
|
|
// Word& local,
|
|
// Supplier s,
|
|
// typename mapmatching::MmORelEdgeStreamCreator<T>::EMode eMode) {
|
|
//
|
|
// // cout << "momapmatchmhtMPointValueMap called" << endl;
|
|
//
|
|
// mapmatching::MmORelEdgeStreamCreator<T>* pCreator =
|
|
// static_cast<mapmatching::MmORelEdgeStreamCreator<T>*>(local.addr);
|
|
// switch (message) {
|
|
//
|
|
// case OPEN: {
|
|
// if(pCreator) {
|
|
// delete pCreator;
|
|
// pCreator = NULL;
|
|
// }
|
|
//
|
|
// // mem(orel)
|
|
// R* orelN = (R*) args[0].addr;
|
|
// MemoryORelObject* orel =
|
|
// getMemORel(orelN,nl->Second(qp->GetType(s)));
|
|
// if(!orel)
|
|
// return 0;
|
|
//
|
|
// // mem(rtree)
|
|
// Q* treeN = (Q*) args[1].addr;
|
|
// string name = treeN->GetValue();
|
|
// // cut blank from the front of the string
|
|
// name = name.substr(1, name.size()-1);
|
|
// MemoryRtreeObject<2>* tree =
|
|
// (MemoryRtreeObject<2>*)catalog->getMMObject(name);
|
|
// if(!tree)
|
|
// return 0;
|
|
//
|
|
// // mem(rel)
|
|
// R* relN = (R*) args[2].addr;
|
|
// MemoryRelObject* rel = getMemRel(relN);
|
|
// if(!rel)
|
|
// return 0;
|
|
//
|
|
// typename mapmatching::MmORelNetwork<T>::OEdgeAttrIndexes Indexes =
|
|
// GetOEdgeAttrIndexes<T>(args, 4);
|
|
//
|
|
// mapmatching::MmORelNetwork<T> Network(orel, tree, rel, Indexes);
|
|
//
|
|
// temporalalgebra::MPoint* pMPoint =
|
|
// static_cast<temporalalgebra::MPoint*>(args[3].addr);
|
|
//
|
|
// // Do Map Matching
|
|
// mapmatching::MmORelNetworkAdapter<T> NetworkAdapter(&Network);
|
|
// mapmatch::MapMatchingMHT MapMatching(&NetworkAdapter, pMPoint);
|
|
//
|
|
// mapmatching::MmORelEdgeStreamCreator<T>* pCreator =
|
|
// new mapmatching::MmORelEdgeStreamCreator<T>(s,NetworkAdapter,eMode);
|
|
// if (!MapMatching.DoMatch(pCreator)) {
|
|
// // Error
|
|
// delete pCreator;
|
|
// pCreator = NULL;
|
|
// }
|
|
//
|
|
// local.setAddr(pCreator);
|
|
// return 0;
|
|
// }
|
|
// case REQUEST: {
|
|
// if (pCreator == NULL) {
|
|
// return CANCEL;
|
|
// }
|
|
// else {
|
|
// result.addr = pCreator->GetNextTuple();
|
|
// return result.addr ? YIELD : CANCEL;
|
|
// }
|
|
// }
|
|
// case CLOSE: {
|
|
// if (pCreator) {
|
|
// delete pCreator;
|
|
// local.addr = NULL;
|
|
// }
|
|
// return 0;
|
|
// }
|
|
// default: {
|
|
// return 0;
|
|
// }
|
|
// }
|
|
// }
|
|
|
|
|
|
// template<class T, class R, class Q>
|
|
// int momapmatchmhtTextValueMap(Word* args,
|
|
// Word& result,
|
|
// int message,
|
|
// Word& local,
|
|
// Supplier s,
|
|
// typename mapmatching::MmORelEdgeStreamCreator<T>::EMode eMode) {
|
|
//
|
|
// // cout << "momapmatchmhtTextValueMap called" << endl;
|
|
//
|
|
// mapmatching::MmORelEdgeStreamCreator<T>* pCreator =
|
|
// static_cast<mapmatching::MmORelEdgeStreamCreator<T>*>(local.addr);
|
|
//
|
|
// switch (message) {
|
|
// case OPEN: {
|
|
//
|
|
// if(pCreator) {
|
|
// delete pCreator;
|
|
// pCreator = NULL;
|
|
// }
|
|
//
|
|
// // mem(orel)
|
|
// R* orelN = (R*) args[0].addr;
|
|
// MemoryORelObject* orel =
|
|
// getMemORel(orelN,nl->Second(qp->GetType(s)));
|
|
// if(!orel)
|
|
// return 0;
|
|
//
|
|
// //mem(rtree)
|
|
// Q* treeN = (Q*) args[1].addr;
|
|
// string name = treeN->GetValue();
|
|
// // cut blank from the front of the string
|
|
// name = name.substr(1, name.size()-1);
|
|
// MemoryRtreeObject<2>* tree =
|
|
// (MemoryRtreeObject<2>*)catalog->getMMObject(name);
|
|
// if(!tree)
|
|
// return 0;
|
|
//
|
|
// // mem(rel)
|
|
// R* relN = (R*) args[2].addr;
|
|
// MemoryRelObject* rel = getMemRel(relN);
|
|
// if(!rel)
|
|
// return 0;;
|
|
//
|
|
// typename mapmatching::MmORelNetwork<T>::OEdgeAttrIndexes Indexes =
|
|
// GetOEdgeAttrIndexes<T>(args, 4);
|
|
//
|
|
// mapmatching::MmORelNetwork<T> Network(orel, tree, rel, Indexes);
|
|
// FText* pFileName = static_cast<FText*>(args[3].addr);
|
|
// std::string strFileName = pFileName->GetValue();
|
|
//
|
|
// // Do Map Matching
|
|
// mapmatching::MmORelNetworkAdapter<T> NetworkAdapter(&Network);
|
|
// mapmatch::MapMatchingMHT MapMatching(&NetworkAdapter, strFileName);
|
|
// mapmatching::MmORelEdgeStreamCreator<T>* pCreator =
|
|
// new mapmatching::MmORelEdgeStreamCreator<T>(s,NetworkAdapter,eMode);
|
|
//
|
|
// if (!MapMatching.DoMatch(pCreator)) {
|
|
// //Error
|
|
// delete pCreator;
|
|
// pCreator = NULL;
|
|
// }
|
|
//
|
|
// local.setAddr(pCreator);
|
|
// return 0;
|
|
// }
|
|
// case REQUEST: {
|
|
// if(pCreator == NULL) {
|
|
// return CANCEL;
|
|
// }
|
|
// else {
|
|
// result.addr = pCreator->GetNextTuple();
|
|
// return result.addr ? YIELD : CANCEL;
|
|
// }
|
|
// }
|
|
// case CLOSE: {
|
|
// if (pCreator) {
|
|
// delete pCreator;
|
|
// local.addr = NULL;
|
|
// }
|
|
// return 0;
|
|
// }
|
|
// default: {
|
|
// return 0;
|
|
// }
|
|
// }
|
|
// }
|
|
|
|
|
|
// template<class T, class R, class Q>
|
|
// int momapmatchmhtStreamValueMap(Word* args,
|
|
// Word& result,
|
|
// int message,
|
|
// Word& local,
|
|
// Supplier s,
|
|
// typename mapmatching::MmORelEdgeStreamCreator<T>::EMode eMode) {
|
|
//
|
|
// // cout << "momapmatchmhtStreamValueMap called" << endl;
|
|
//
|
|
// mapmatching::MmORelEdgeStreamCreator<T>* pCreator =
|
|
// static_cast<mapmatching::MmORelEdgeStreamCreator<T>*>(local.addr);
|
|
//
|
|
// switch (message) {
|
|
// case OPEN: {
|
|
//
|
|
// if (pCreator != NULL) {
|
|
// delete pCreator;
|
|
// pCreator = NULL;
|
|
// }
|
|
//
|
|
// // mem(orel)
|
|
// R* orelN = (R*) args[0].addr;
|
|
// MemoryORelObject* orel = getMemORel(orelN,nl->Second(qp->GetType(s)));
|
|
// if(!orel)
|
|
// return 0;
|
|
//
|
|
// // mem(rtree)
|
|
// Q* treeN = (Q*) args[1].addr;
|
|
// string name = treeN->GetValue();
|
|
// // cut blank from the front of the string
|
|
// name = name.substr(1, name.size()-1);
|
|
// MemoryRtreeObject<2>* tree =
|
|
// (MemoryRtreeObject<2>*)catalog->getMMObject(name);
|
|
// if(!tree)
|
|
// return 0;
|
|
//
|
|
// // mem(rel)
|
|
// R* relN = (R*) args[2].addr;
|
|
// MemoryRelObject* rel = getMemRel(relN);
|
|
// if(!rel)
|
|
// return 0;
|
|
//
|
|
// typename mapmatching::MmORelNetwork<T>::OEdgeAttrIndexes Indexes =
|
|
// GetOEdgeAttrIndexes<T>(args, 4);
|
|
//
|
|
// mapmatching::MmORelNetwork<T> Network(orel, tree, rel, Indexes);
|
|
//
|
|
// shared_ptr<mapmatch::MapMatchDataContainer> pContData =
|
|
// GetMMDataFromTupleStream(args[3].addr, args, 4 + 9);
|
|
// // 9 OEdge-Attr-Indexes
|
|
// // Do Map Matching
|
|
// mapmatching::MmORelNetworkAdapter<T> NetworkAdapter(&Network);
|
|
// mapmatch::MapMatchingMHT MapMatching(&NetworkAdapter, pContData);
|
|
// mapmatching::MmORelEdgeStreamCreator<T>* pCreator =
|
|
// new mapmatching::MmORelEdgeStreamCreator<T>(s,NetworkAdapter,eMode);
|
|
//
|
|
// if (!MapMatching.DoMatch(pCreator)) {
|
|
// //Error
|
|
// delete pCreator;
|
|
// pCreator = NULL;
|
|
// }
|
|
//
|
|
// local.setAddr(pCreator);
|
|
// return 0;
|
|
// }
|
|
// case REQUEST: {
|
|
// if (pCreator == NULL) {
|
|
// return CANCEL;
|
|
// }
|
|
// else {
|
|
// result.addr = pCreator->GetNextTuple();
|
|
// return result.addr ? YIELD : CANCEL;
|
|
// }
|
|
// }
|
|
// case CLOSE: {
|
|
// if (pCreator) {
|
|
// delete pCreator;
|
|
// local.addr = NULL;
|
|
// }
|
|
// return 0;
|
|
// }
|
|
// default: {
|
|
// return 0;
|
|
// }
|
|
// }
|
|
// }
|
|
|
|
|
|
// template<class T, class R, class Q>
|
|
// int momapmatchmhtMPointVMT(Word* args,
|
|
// Word& result,
|
|
// int message,
|
|
// Word& local,
|
|
// Supplier in_xSupplier) {
|
|
//
|
|
// return momapmatchmhtMPointValueMap<T,R,Q>(
|
|
// args,
|
|
// result,
|
|
// message,
|
|
// local,
|
|
// in_xSupplier,
|
|
// mapmatching::MmORelEdgeStreamCreator<T>::MODE_EDGES);
|
|
// }
|
|
//
|
|
//
|
|
// template<class T, class R, class Q>
|
|
// int momapmatchmhtTextVMT(Word* args,
|
|
// Word& result,
|
|
// int message,
|
|
// Word& local,
|
|
// Supplier in_xSupplier) {
|
|
//
|
|
// return momapmatchmhtTextValueMap<T,R,Q>(
|
|
// args,
|
|
// result,
|
|
// message,
|
|
// local,
|
|
// in_xSupplier,
|
|
// mapmatching::MmORelEdgeStreamCreator<T>::MODE_EDGES);
|
|
// }
|
|
|
|
|
|
// template<class T, class R, class Q>
|
|
// int momapmatchmhtStreamVMT(Word* args,
|
|
// Word& result,
|
|
// int message,
|
|
// Word& local,
|
|
// Supplier in_xSupplier) {
|
|
//
|
|
// return momapmatchmhtStreamValueMap<T,R,Q>(
|
|
// args,
|
|
// result,
|
|
// message,
|
|
// local,
|
|
// in_xSupplier,
|
|
// mapmatching::MmORelEdgeStreamCreator<T>::MODE_EDGES);
|
|
// }
|
|
|
|
|
|
/*
|
|
|
|
7.38.4 Selection Function ~momapmatchmht~
|
|
|
|
*/
|
|
// int momapmatchmhtSelect(ListExpr args) {
|
|
//
|
|
// NList type(args);
|
|
// if (type.length() == 4) {
|
|
//
|
|
// if (type.fourth().isSymbol(temporalalgebra::MPoint::BasicType()))
|
|
// return 0/* + offset*/;
|
|
//
|
|
// else if (type.fourth().isSymbol(FText::BasicType()))
|
|
// return 1 /*+ offset*/;
|
|
//
|
|
// else if (listutils::isTupleStream(type.fourth().listExpr()))
|
|
// return 2/* + offset*/;
|
|
//
|
|
// else
|
|
// return -1;
|
|
// }
|
|
// else
|
|
// return -1;
|
|
// }
|
|
|
|
|
|
// ValueMapping momapmatchmhtVM[] = {
|
|
// momapmatchmhtMPointVMT<CcInt,CcString,Mem>,
|
|
// momapmatchmhtTextVMT<CcInt,CcString,Mem>,
|
|
// momapmatchmhtStreamVMT<CcInt,CcString,Mem>
|
|
// };
|
|
|
|
|
|
/*
|
|
|
|
7.38.5 Description of operator ~momapmatchmht~
|
|
|
|
*/
|
|
// OperatorSpec momapmatchmhtSpec(
|
|
// "mem(orel(tuple(x))) x mem(rtree) x mem(rel(tuple(x)) x var "
|
|
// "-> stream(tuple(x))",
|
|
// "momapmatchmht (_,_,_,_)",
|
|
// "map matching with a main memory ordered relation "
|
|
// "Result: Tuples of matched edges with timestamps",
|
|
// "query momapmatchmht('Edges','EdgeIndex_Box_rtree', "
|
|
// "'EdgeIndex','Trk_MapMatchTest.gpx') count"
|
|
// );
|
|
|
|
|
|
/*
|
|
7.38.5 Instance of operator ~momapmatchmht~
|
|
|
|
*/
|
|
// Operator momapmatchmhtOp (
|
|
// "momapmatchmht",
|
|
// momapmatchmhtSpec.getStr(),
|
|
// 3,
|
|
// momapmatchmhtVM,
|
|
// momapmatchmhtSelect,
|
|
// momapmatchmhtTypeMap
|
|
// );
|
|
|
|
|
|
|
|
GenTC<Mem> MemTC;
|
|
|
|
|
|
|
|
TypeConstructor MPointerTC(
|
|
MPointer::BasicType(),
|
|
MPointer::Property,
|
|
MPointer::Out, MPointer::In,
|
|
0,0,
|
|
MPointer::Create, MPointer::Delete,
|
|
MPointer::Open, MPointer::Save,
|
|
MPointer::Close, MPointer::Clone,
|
|
MPointer::Cast,
|
|
MPointer::SizeOf,
|
|
MPointer::TypeCheck
|
|
);
|
|
|
|
|
|
/*
|
|
|
|
9 Operations on Attribute vectors
|
|
|
|
9.1 collect[_]mvector
|
|
|
|
stream(DATA) x string x bool -> bool;
|
|
|
|
*/
|
|
ListExpr collect_mvectorTM(ListExpr args){
|
|
if(!nl->HasLength(args,2)){
|
|
return listutils::typeError("2 arguments expected");
|
|
}
|
|
string err = "stream(DATA) x bool expected";
|
|
if( !Stream<Attribute>::checkType(nl->First(args))
|
|
||!CcBool::checkType(nl->Second(args))){
|
|
return listutils::typeError(err);
|
|
}
|
|
return MPointer::wrapType(Mem::wrapType(MemoryVectorObject::wrapType(
|
|
nl->Second(nl->First(args)))));
|
|
}
|
|
|
|
int collect_mvectorVM(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
CcBool* flob = (CcBool*) args[1].addr;
|
|
result = qp->ResultStorage(s);
|
|
MPointer* res = (MPointer*) result.addr;
|
|
if(!flob->IsDefined()){
|
|
res->setPointer(0);
|
|
return 0;
|
|
}
|
|
string db = SecondoSystem::GetInstance()->GetDatabaseName();
|
|
ListExpr st = qp->GetType(qp->GetSon(s,0));
|
|
st = nl->Second(qp->GetType(s));
|
|
string type = nl->ToString(st);
|
|
MemoryVectorObject* v = new MemoryVectorObject(flob->GetValue(),db,type);
|
|
Stream<Attribute> stream(args[0]);
|
|
stream.open();
|
|
Attribute* a;
|
|
while((a = stream.request())){
|
|
v->add(a,true);
|
|
a->DeleteIfAllowed();
|
|
}
|
|
stream.close();
|
|
res->setPointer(v);
|
|
v->deleteIfAllowed();
|
|
return 0;
|
|
}
|
|
|
|
OperatorSpec collect_mvectorSpec(
|
|
"stream(X) x bool -> mpointer(mem(mvector(X))) , X in DATA",
|
|
" _ collect_mvector[_]",
|
|
" Collects a stream of attributes into a main memory"
|
|
" vector. The second argument specifies whether "
|
|
" flobs should be loaded into memory too.",
|
|
" query plz feed projecttransformstream[PLZ] collect_mvector[TRUE] "
|
|
);
|
|
|
|
Operator collect_mvectorOp(
|
|
"collect_mvector",
|
|
collect_mvectorSpec.getStr(),
|
|
collect_mvectorVM,
|
|
Operator::SimpleSelect,
|
|
collect_mvectorTM
|
|
);
|
|
|
|
|
|
/*
|
|
9.2 sizemv
|
|
|
|
Returns the size of an mvector.
|
|
|
|
*/
|
|
|
|
|
|
ListExpr sizemvTM(ListExpr args){
|
|
if(!nl->HasLength(args,1)){
|
|
return listutils::typeError("one arg expected");
|
|
}
|
|
ListExpr a;
|
|
if(!getMemSubType(nl->First(args),a)){
|
|
return listutils::typeError("first argument is not a memory object");
|
|
}
|
|
if(!MemoryVectorObject::checkType(a)){
|
|
return listutils::typeError("argument is not an mvector");
|
|
}
|
|
return listutils::basicSymbol<CcInt>();
|
|
}
|
|
|
|
|
|
template<class T>
|
|
int sizemvVMT(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
|
|
T* arg = (T*) args[0].addr;
|
|
result = qp->ResultStorage(s);
|
|
CcInt* res = (CcInt*) result.addr;
|
|
MemoryVectorObject* mv = getMVector(arg);
|
|
if(!mv){
|
|
res->SetDefined(false);
|
|
} else {
|
|
res->Set(true, mv->size());
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
ValueMapping sizemvVM[] = {
|
|
sizemvVMT<Mem>,
|
|
sizemvVMT<MPointer>
|
|
};
|
|
|
|
|
|
int sizemvSelect(ListExpr args){
|
|
ListExpr a = nl->First(args);
|
|
if(Mem::checkType(a)) return 0;
|
|
if(MPointer::checkType(a)) return 1;
|
|
return -1;
|
|
}
|
|
|
|
OperatorSpec sizemvSpec(
|
|
"{mem,mpointer} -> int ",
|
|
"sizemv(_)",
|
|
"Returns the size of a memory vector.",
|
|
"query sizemv(v1)"
|
|
|
|
);
|
|
|
|
Operator sizemvOp(
|
|
"sizemv",
|
|
sizemvSpec.getStr(),
|
|
2,
|
|
sizemvVM,
|
|
sizemvSelect,
|
|
sizemvTM
|
|
|
|
);
|
|
|
|
|
|
|
|
/*
|
|
9.3 getmv
|
|
|
|
Returns an element of an mvector.
|
|
|
|
*/
|
|
|
|
|
|
ListExpr getmvTM(ListExpr args){
|
|
if(!nl->HasLength(args,2)){
|
|
return listutils::typeError("one arg expected");
|
|
}
|
|
if(!CcInt::checkType(nl->Second(args))){
|
|
return listutils::typeError("Second arg has to be an int");
|
|
}
|
|
ListExpr a;
|
|
if(!getMemSubType(nl->First(args),a)){
|
|
return listutils::typeError("first arg is not a memory object");
|
|
}
|
|
if(!MemoryVectorObject::checkType(a)){
|
|
return listutils::typeError("argument is not an mvector");
|
|
}
|
|
return listutils::basicSymbol<CcInt>();
|
|
}
|
|
|
|
|
|
template<class T>
|
|
int getmvVMT(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
|
|
result = qp->ResultStorage(s);
|
|
Attribute* res = (Attribute*) result.addr;
|
|
CcInt* spos = (CcInt*) args[1].addr;
|
|
if(!spos->IsDefined() ){
|
|
res->SetDefined(false);
|
|
return 0;
|
|
}
|
|
int pos = spos->GetValue();
|
|
|
|
T* arg = (T*) args[0].addr;
|
|
|
|
MemoryVectorObject* mv = getMVector(arg);
|
|
if(!mv){
|
|
res->SetDefined(false);
|
|
} else {
|
|
if(pos<0 || (size_t)pos>=mv->size()){
|
|
res->SetDefined(0);
|
|
} else {
|
|
res->CopyFrom(mv->get(pos));
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
ValueMapping getmvVM[] = {
|
|
getmvVMT<Mem>,
|
|
getmvVMT<MPointer>
|
|
};
|
|
|
|
|
|
int getmvSelect(ListExpr args){
|
|
ListExpr a = nl->First(args);
|
|
if(Mem::checkType(a)) return 0;
|
|
if(MPointer::checkType(a)) return 1;
|
|
return -1;
|
|
}
|
|
|
|
OperatorSpec getmvSpec(
|
|
"{mem,mpointer} x int -> DATA ",
|
|
"_ getmv[_ ]",
|
|
"Returns an specified element of an mvector",
|
|
"query v1 getmv[42]"
|
|
);
|
|
|
|
Operator getmvOp(
|
|
"getmv",
|
|
getmvSpec.getStr(),
|
|
2,
|
|
getmvVM,
|
|
getmvSelect,
|
|
getmvTM
|
|
);
|
|
|
|
|
|
/*
|
|
9.3 putmv
|
|
|
|
Changes a element of an mvector. Returns the old element.
|
|
|
|
*/
|
|
|
|
|
|
ListExpr putmvTM(ListExpr args){
|
|
if(!nl->HasLength(args,3)){
|
|
return listutils::typeError("one arg expected");
|
|
}
|
|
if(!CcInt::checkType(nl->Second(args))){
|
|
return listutils::typeError("Second arg has to be an int");
|
|
}
|
|
ListExpr newValue = nl->Third(args);
|
|
if(!Attribute::checkType(newValue)){
|
|
return listutils::typeError("thir arg not in kind DATA");
|
|
}
|
|
|
|
ListExpr a;
|
|
if(!getMemSubType(nl->First(args),a)){
|
|
return listutils::typeError("fisrt arg is not a memory object");
|
|
}
|
|
if(!MemoryVectorObject::checkType(a)){
|
|
return listutils::typeError("argument is not an mvector");
|
|
}
|
|
if(!nl->Equal(nl->Second(a),newValue)){
|
|
return listutils::typeError("new value has another type than the vector");
|
|
}
|
|
return listutils::basicSymbol<CcInt>();
|
|
}
|
|
|
|
|
|
template<class T>
|
|
int putmvVMT(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
|
|
result = qp->ResultStorage(s);
|
|
Attribute* res = (Attribute*) result.addr;
|
|
CcInt* spos = (CcInt*) args[1].addr;
|
|
if(!spos->IsDefined() ){
|
|
res->SetDefined(false);
|
|
return 0;
|
|
}
|
|
int pos = spos->GetValue();
|
|
|
|
Attribute* attr = (Attribute*) args[2].addr;
|
|
|
|
T* arg = (T*) args[0].addr;
|
|
|
|
MemoryVectorObject* mv = getMVector(arg);
|
|
if(!mv){
|
|
res->SetDefined(false);
|
|
} else {
|
|
if(pos<0 || (size_t)pos>=mv->size()){
|
|
res->SetDefined(0);
|
|
} else {
|
|
Attribute* old = mv->get(pos);
|
|
mv->put(pos, attr, true);
|
|
res->CopyFrom(old);
|
|
old->DeleteIfAllowed();
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
ValueMapping putmvVM[] = {
|
|
putmvVMT<Mem>,
|
|
putmvVMT<MPointer>
|
|
};
|
|
|
|
|
|
int putmvSelect(ListExpr args){
|
|
ListExpr a = nl->First(args);
|
|
if(Mem::checkType(a)) return 0;
|
|
if(MPointer::checkType(a)) return 1;
|
|
return -1;
|
|
}
|
|
|
|
OperatorSpec putmvSpec(
|
|
"{mem,mpointer} x int x DATA -> DATA ",
|
|
"_ getmv[_ ]",
|
|
"Replaces an specified element in an mvector, returns the old element.",
|
|
"query v1 putmv[17, 'newValue'] "
|
|
);
|
|
|
|
Operator putmvOp(
|
|
"putmv",
|
|
putmvSpec.getStr(),
|
|
2,
|
|
putmvVM,
|
|
putmvSelect,
|
|
putmvTM
|
|
);
|
|
|
|
/*
|
|
9.5 sizemv
|
|
|
|
Check whether an mvector is sorted.
|
|
|
|
*/
|
|
|
|
|
|
ListExpr isSortedmvTM(ListExpr args){
|
|
if(!nl->HasLength(args,1)){
|
|
return listutils::typeError("one arg expected");
|
|
}
|
|
ListExpr a;
|
|
if(!getMemSubType(nl->First(args),a)){
|
|
return listutils::typeError("first argument is not a memory object");
|
|
}
|
|
if(!MemoryVectorObject::checkType(a)){
|
|
return listutils::typeError("argument is not an mvector");
|
|
}
|
|
return listutils::basicSymbol<CcBool>();
|
|
}
|
|
|
|
|
|
template<class T>
|
|
int isSortedmvVMT(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
|
|
T* arg = (T*) args[0].addr;
|
|
result = qp->ResultStorage(s);
|
|
CcBool* res = (CcBool*) result.addr;
|
|
MemoryVectorObject* mv = getMVector(arg);
|
|
if(!mv){
|
|
res->SetDefined(false);
|
|
} else {
|
|
res->Set(true, mv->isSorted());
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
ValueMapping isSortedmvVM[] = {
|
|
isSortedmvVMT<Mem>,
|
|
isSortedmvVMT<MPointer>
|
|
};
|
|
|
|
|
|
int isSortedmvSelect(ListExpr args){
|
|
ListExpr a = nl->First(args);
|
|
if(Mem::checkType(a)) return 0;
|
|
if(MPointer::checkType(a)) return 1;
|
|
return -1;
|
|
}
|
|
|
|
OperatorSpec isSortedmvSpec(
|
|
"{mem,mpointer} -> bool ",
|
|
"issortedmv(_)",
|
|
"Checks whether an mvector is known as sorted",
|
|
"query isSortedmv(v1)"
|
|
|
|
);
|
|
|
|
Operator isSortedmvOp(
|
|
"isSortedmv",
|
|
isSortedmvSpec.getStr(),
|
|
2,
|
|
isSortedmvVM,
|
|
isSortedmvSelect,
|
|
isSortedmvTM
|
|
);
|
|
|
|
|
|
|
|
/*
|
|
9.5 sortmv
|
|
|
|
Check whether an mvector is sorted.
|
|
|
|
*/
|
|
|
|
|
|
ListExpr sortmvTM(ListExpr args){
|
|
if(!nl->HasLength(args,1)){
|
|
return listutils::typeError("one arg expected");
|
|
}
|
|
ListExpr arg1 = nl->First(args);
|
|
if(MPointer::checkType(arg1)){
|
|
arg1 = nl->Second(arg1);
|
|
}
|
|
if(!Mem::checkType(arg1)){
|
|
return listutils::typeError("argument not of type mpointer or mem");
|
|
}
|
|
arg1 = nl->Second(arg1);
|
|
if(!MemoryVectorObject::checkType(arg1)){
|
|
return listutils::typeError("argument is not an mvector");
|
|
}
|
|
return MPointer::wrapType(Mem::wrapType(arg1));
|
|
|
|
}
|
|
|
|
|
|
template<class T>
|
|
int sortmvVMT(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
|
|
T* arg = (T*) args[0].addr;
|
|
result = qp->ResultStorage(s);
|
|
MPointer* res = (MPointer*) result.addr;
|
|
MemoryVectorObject* mv = getMVector(arg);
|
|
if(mv){
|
|
mv->sort();
|
|
}
|
|
res->setPointer(mv);
|
|
return 0;
|
|
}
|
|
|
|
ValueMapping sortmvVM[] = {
|
|
sortmvVMT<Mem>,
|
|
sortmvVMT<MPointer>
|
|
};
|
|
|
|
|
|
int sortmvSelect(ListExpr args){
|
|
ListExpr a = nl->First(args);
|
|
if(Mem::checkType(a)) return 0;
|
|
if(MPointer::checkType(a)) return 1;
|
|
return -1;
|
|
}
|
|
|
|
OperatorSpec sortmvSpec(
|
|
"{mem,string,mpointer} -> mpointer ",
|
|
"sort(_)",
|
|
"Sorts an mvector.",
|
|
"query sort(v1)"
|
|
|
|
);
|
|
|
|
Operator sortmvOp(
|
|
"sortmv",
|
|
sortmvSpec.getStr(),
|
|
2,
|
|
sortmvVM,
|
|
sortmvSelect,
|
|
sortmvTM
|
|
);
|
|
|
|
/*
|
|
9.8 feedmv
|
|
|
|
Feeds the elements of an mvector into a stream.
|
|
|
|
*/
|
|
|
|
|
|
ListExpr feedmvTM(ListExpr args){
|
|
if(!nl->HasLength(args,1)){
|
|
return listutils::typeError("one arg expected");
|
|
}
|
|
ListExpr a;
|
|
if(!getMemSubType(nl->First(args),a)){
|
|
return listutils::typeError("first arg is not a memory object");
|
|
}
|
|
if(!MemoryVectorObject::checkType(a)){
|
|
return listutils::typeError("argument is not an mvector");
|
|
}
|
|
return nl->TwoElemList( listutils::basicSymbol<Stream<Attribute> >(),
|
|
nl->Second(a));
|
|
|
|
}
|
|
|
|
class feedmvInfo{
|
|
public:
|
|
feedmvInfo(MemoryVectorObject* _v): v(_v), pos(0), max(_v->size()){}
|
|
|
|
~feedmvInfo(){}
|
|
|
|
Attribute* next(){
|
|
if(pos>=max){
|
|
return 0;
|
|
}
|
|
return v->get(pos++)->Copy();
|
|
}
|
|
|
|
private:
|
|
MemoryVectorObject* v;
|
|
size_t pos;
|
|
size_t max;
|
|
|
|
};
|
|
|
|
|
|
template<class T>
|
|
int feedmvVMT(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
|
|
feedmvInfo* li = (feedmvInfo*) local.addr;
|
|
switch(message){
|
|
case OPEN: {
|
|
if(li){
|
|
delete li;
|
|
local.addr = 0;
|
|
}
|
|
T* arg = (T*) args[0].addr;
|
|
MemoryVectorObject* mv = getMVector(arg);
|
|
if(mv){
|
|
local.addr = new feedmvInfo(mv);
|
|
}
|
|
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 -1;
|
|
}
|
|
|
|
ValueMapping feedmvVM[] = {
|
|
feedmvVMT<Mem>,
|
|
feedmvVMT<MPointer>
|
|
};
|
|
|
|
|
|
int feedmvSelect(ListExpr args){
|
|
ListExpr a = nl->First(args);
|
|
if(Mem::checkType(a)) return 0;
|
|
if(MPointer::checkType(a)) return 1;
|
|
return -1;
|
|
}
|
|
|
|
OperatorSpec feedmvSpec(
|
|
"{mem,mpointer} -> stream(DATA) ",
|
|
"_ feedmv",
|
|
"feeds an mvector.",
|
|
"query v1 feedmv count"
|
|
);
|
|
|
|
Operator feedmvOp(
|
|
"feedmv",
|
|
feedmvSpec.getStr(),
|
|
2,
|
|
feedmvVM,
|
|
feedmvSelect,
|
|
feedmvTM
|
|
);
|
|
|
|
/*
|
|
9.8 findmv
|
|
|
|
Returns the position within an sorted mvector where
|
|
an element is located or would be inserted (moving
|
|
elements to right).
|
|
|
|
*/
|
|
|
|
|
|
ListExpr findmvTM(ListExpr args){
|
|
if(!nl->HasLength(args,2)){
|
|
return listutils::typeError("two arg expected");
|
|
}
|
|
ListExpr v = nl->Second(args);
|
|
if(!Attribute::checkType(v)){
|
|
return listutils::typeError("second arg is not in kind DATA");
|
|
}
|
|
ListExpr a;
|
|
if(!getMemSubType(nl->First(args),a)){
|
|
return listutils::typeError("first arg is not a memory object");
|
|
}
|
|
|
|
if(!MemoryVectorObject::checkType(a)){
|
|
return listutils::typeError("argument is not an mvector");
|
|
}
|
|
ListExpr sa = nl->Second(a);
|
|
if(!nl->Equal(sa,v)){
|
|
return listutils::typeError("subtype of vector and search type differ");
|
|
}
|
|
|
|
return listutils::basicSymbol<CcInt>();
|
|
}
|
|
|
|
|
|
template<class T>
|
|
int findmvVMT(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
|
|
T* arg = (T*) args[0].addr;
|
|
result = qp->ResultStorage(s);
|
|
CcInt* res = (CcInt*) result.addr;
|
|
MemoryVectorObject* mv = getMVector(arg);
|
|
if(!mv){
|
|
res->SetDefined(false);
|
|
return 0;
|
|
}
|
|
if(!mv->isSorted()){
|
|
res->SetDefined(false);
|
|
return 0;
|
|
}
|
|
if(mv->size()<1){
|
|
res->Set(true,0);
|
|
return 0;
|
|
}
|
|
Attribute* attr = (Attribute*) args[1].addr;
|
|
res->Set(true,mv->binSearch(attr));
|
|
return 0;
|
|
}
|
|
|
|
ValueMapping findmvVM[] = {
|
|
findmvVMT<Mem>,
|
|
findmvVMT<MPointer>
|
|
};
|
|
|
|
|
|
int findmvSelect(ListExpr args){
|
|
ListExpr a = nl->First(args);
|
|
if(Mem::checkType(a)) return 0;
|
|
if(MPointer::checkType(a)) return 1;
|
|
return -1;
|
|
}
|
|
|
|
OperatorSpec findmvSpec(
|
|
"{mem, mpointer} x DATA -> int ",
|
|
"findmv(_)",
|
|
"Returns the position (or a potential insertion position) "
|
|
"of a value within an ordered memory vector.",
|
|
"query findmv(v1, 'Value' )"
|
|
);
|
|
|
|
Operator findmvOp(
|
|
"findmv",
|
|
findmvSpec.getStr(),
|
|
2,
|
|
findmvVM,
|
|
findmvSelect,
|
|
findmvTM
|
|
);
|
|
|
|
|
|
/*
|
|
9.8 matchbelow
|
|
|
|
Returns the element of an mvector that is smaller or equal than
|
|
a given object.
|
|
|
|
|
|
*/
|
|
|
|
|
|
ListExpr matchbelowmvTM(ListExpr args){
|
|
if(!nl->HasLength(args,2)){
|
|
return listutils::typeError("two arg expected");
|
|
}
|
|
ListExpr v = nl->Second(args);
|
|
if(!Attribute::checkType(v)){
|
|
return listutils::typeError("second arg is not in kind DATA");
|
|
}
|
|
ListExpr a;
|
|
if(!getMemSubType(nl->First(args),a)){
|
|
return listutils::typeError("first arg is not a memory object");
|
|
}
|
|
if(!MemoryVectorObject::checkType(a)){
|
|
return listutils::typeError("argument is not an mvector");
|
|
}
|
|
|
|
ListExpr sa = nl->Second(a);
|
|
if(!nl->Equal(sa,v)){
|
|
return listutils::typeError("subtype of vector and search type differ");
|
|
}
|
|
return sa;
|
|
}
|
|
|
|
|
|
template<class T>
|
|
int matchbelowmvVMT(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
|
|
T* arg = (T*) args[0].addr;
|
|
result = qp->ResultStorage(s);
|
|
Attribute* res = (Attribute*) result.addr;
|
|
MemoryVectorObject* mv = getMVector(arg);
|
|
if(!mv){
|
|
res->SetDefined(false);
|
|
return 0;
|
|
}
|
|
Attribute* attr = (Attribute*) args[1].addr;
|
|
Attribute* resv = mv->matchBelow(attr);
|
|
if(!resv){
|
|
res->SetDefined(false);
|
|
return 0;
|
|
}
|
|
res->CopyFrom(resv);
|
|
return 0;
|
|
}
|
|
|
|
ValueMapping matchbelowmvVM[] = {
|
|
matchbelowmvVMT<Mem>,
|
|
matchbelowmvVMT<MPointer>
|
|
};
|
|
|
|
|
|
int matchbelowmvSelect(ListExpr args){
|
|
ListExpr a = nl->First(args);
|
|
if(Mem::checkType(a)) return 0;
|
|
if(MPointer::checkType(a)) return 1;
|
|
return -1;
|
|
}
|
|
|
|
OperatorSpec matchbelowmvSpec(
|
|
"{mem, mpointer} x DATA -> DATA ",
|
|
" _ matchbelowmv[_]",
|
|
"Returns the element of an mvector that is "
|
|
"smaller or equal to agiven object.",
|
|
"query v1 matchbelowmv( 'Value' )"
|
|
|
|
);
|
|
|
|
Operator matchbelowmvOp(
|
|
"matchbelowmv",
|
|
matchbelowmvSpec.getStr(),
|
|
2,
|
|
matchbelowmvVM,
|
|
matchbelowmvSelect,
|
|
matchbelowmvTM
|
|
);
|
|
|
|
|
|
/*
|
|
9.9 Operator insertmv
|
|
|
|
*/
|
|
ListExpr insertmvTM(ListExpr args){
|
|
if(!nl->HasLength(args,2) && !nl->HasLength(args,3)){
|
|
return listutils::typeError("two or three args expected");
|
|
}
|
|
|
|
ListExpr stream = nl->First(args);
|
|
ListExpr attrType = nl->TheEmptyList();
|
|
ListExpr vector = nl->TheEmptyList();
|
|
int index = 0;
|
|
if(nl->HasLength(args,2)){
|
|
if(!Stream<Attribute>::checkType(stream)){
|
|
return listutils::typeError("If two arguments are given, the first one "
|
|
"must be a stream of attributes");
|
|
}
|
|
attrType = nl->Second(stream);
|
|
vector = nl->Second(args);
|
|
} else { // three arguments
|
|
if(!Stream<Tuple>::checkType(stream)){
|
|
return listutils::typeError("If 3 arguments are given, the first one "
|
|
"must be a stream of tuples");
|
|
}
|
|
ListExpr attrNameList = nl->Second(args);
|
|
if(!listutils::isSymbol(attrNameList)){
|
|
return listutils::typeError("invalid attribute name as 2nd arg");
|
|
}
|
|
string attrName = nl->SymbolValue(attrNameList);
|
|
ListExpr attrList = nl->Second(nl->Second(stream));
|
|
index = listutils::findAttribute(attrList,attrName,attrType);
|
|
if(!index){
|
|
return listutils::typeError("Attribute " + attrName
|
|
+ " not part of the tuple in stream");
|
|
}
|
|
vector = nl->Third(args);
|
|
}
|
|
|
|
if(!getMemSubType(vector,vector)){
|
|
return listutils::typeError("the last element is not a memory object");
|
|
}
|
|
if(!MemoryVectorObject::checkType(vector)){
|
|
return listutils::typeError("last element is not a memory vector");
|
|
}
|
|
if(!nl->Equal(attrType, nl->Second(vector))){
|
|
return listutils::typeError("stream type and vector type differ");
|
|
}
|
|
if(nl->HasLength(args,2)){
|
|
return stream;
|
|
} else {
|
|
return nl->ThreeElemList(nl->SymbolAtom(Symbols::APPEND()),
|
|
nl->OneElemList( nl->IntAtom(index-1)),
|
|
stream);
|
|
}
|
|
}
|
|
|
|
|
|
class insertmvAttrInfo{
|
|
public:
|
|
insertmvAttrInfo(Word& _stream, MemoryVectorObject* _v):
|
|
stream(_stream), v(_v){
|
|
stream.open();
|
|
}
|
|
~insertmvAttrInfo(){
|
|
stream.close();
|
|
}
|
|
|
|
Attribute* next(){
|
|
Attribute* a = stream.request();
|
|
if(a){
|
|
v->add(a,true);
|
|
}
|
|
return a;
|
|
}
|
|
|
|
private:
|
|
Stream<Attribute> stream;
|
|
MemoryVectorObject* v;
|
|
};
|
|
|
|
|
|
template<class T>
|
|
int insertmvAttrVMT(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
|
|
insertmvAttrInfo* li = (insertmvAttrInfo*) local.addr;
|
|
switch(message){
|
|
case OPEN: {
|
|
if(li){
|
|
delete li;
|
|
local.addr = 0;
|
|
}
|
|
T* vn = (T*) args[1].addr;
|
|
MemoryVectorObject* v = getMVector(vn);
|
|
if(v==0){
|
|
return 0;
|
|
}
|
|
local.addr = new insertmvAttrInfo(args[0],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;
|
|
}
|
|
|
|
class insertmvTupleInfo{
|
|
public:
|
|
insertmvTupleInfo(Word& _stream, MemoryVectorObject* _v, int _index):
|
|
stream(_stream), v(_v), index(_index){
|
|
stream.open();
|
|
}
|
|
~insertmvTupleInfo(){
|
|
stream.close();
|
|
}
|
|
|
|
Tuple* next(){
|
|
Tuple* t = stream.request();
|
|
if(t){
|
|
v->add(t->GetAttribute(index), true);
|
|
}
|
|
return t;
|
|
}
|
|
|
|
private:
|
|
Stream<Tuple> stream;
|
|
MemoryVectorObject* v;
|
|
int index;
|
|
};
|
|
|
|
|
|
template<class T>
|
|
int insertmvTupleVMT(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
|
|
insertmvTupleInfo* li = (insertmvTupleInfo*) local.addr;
|
|
switch(message){
|
|
case OPEN: {
|
|
if(li){
|
|
delete li;
|
|
local.addr = 0;
|
|
}
|
|
T* vn = (T*) args[2].addr;
|
|
MemoryVectorObject* v = getMVector(vn);
|
|
if(v==0){
|
|
return 0;
|
|
}
|
|
int index = ((CcInt*) args[3].addr)->GetValue();
|
|
local.addr = new insertmvTupleInfo(args[0],v,index);
|
|
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;
|
|
}
|
|
|
|
ValueMapping insertmvVM[] = {
|
|
insertmvAttrVMT<Mem>,
|
|
insertmvAttrVMT<MPointer>,
|
|
insertmvTupleVMT<Mem>,
|
|
insertmvTupleVMT<MPointer>
|
|
};
|
|
|
|
int insertmvSelect(ListExpr args){
|
|
|
|
int n1 = -2;
|
|
ListExpr vt;
|
|
if(nl->HasLength(args,2)){
|
|
n1 = 0;
|
|
vt = nl->Second(args);
|
|
} else {
|
|
n1 = 2;
|
|
vt = nl->Third(args);
|
|
}
|
|
if(Mem::checkType(vt)){
|
|
return n1;
|
|
}
|
|
if(MPointer::checkType(vt)){
|
|
return n1+1;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
OperatorSpec insertmvSpec(
|
|
"stream(A) x mvector -> stream(A) | "
|
|
"stream(tuple(...)) x ID x mvector -> stream(tuple)",
|
|
" _ insertmv[_,_] ",
|
|
"Appends elements from a stream to a main memory vector.",
|
|
" query ten feed insertmv[No, tv] count"
|
|
);
|
|
|
|
|
|
Operator insertmvOp(
|
|
"insertmv",
|
|
insertmvSpec.getStr(),
|
|
4,
|
|
insertmvVM,
|
|
insertmvSelect,
|
|
insertmvTM
|
|
);
|
|
|
|
|
|
/*
|
|
10 MPointer Creation
|
|
|
|
*/
|
|
ListExpr pwrapTM(ListExpr args){
|
|
if(!nl->HasLength(args,1)){
|
|
return listutils::typeError("pwrap needs one argument");
|
|
}
|
|
ListExpr arg = nl->First(args);
|
|
if(!nl->HasLength(arg,2)){
|
|
return listutils::typeError("internal error");
|
|
}
|
|
ListExpr t = nl->First(arg);
|
|
if( !CcString::checkType(t)
|
|
&&!Mem::checkType(t)){
|
|
return listutils::typeError("string or mem(...) expected");
|
|
}
|
|
|
|
ListExpr motype;
|
|
if(CcString::checkType(t)) {
|
|
ListExpr v = nl->Second(arg);
|
|
if(nl->AtomType(v)!=StringType){
|
|
return listutils::typeError("only constant objects allowed");
|
|
}
|
|
string n = nl->StringValue(v);
|
|
MemoryObject* mo = catalog->getMMObject(n);
|
|
if(mo==0){
|
|
return listutils::typeError("No mm object with name " + n + " found");
|
|
}
|
|
motype = mo->getType();
|
|
} else {
|
|
motype = t;
|
|
}
|
|
ListExpr res = nl->TwoElemList(listutils::basicSymbol<MPointer>(),
|
|
motype);
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
template<class T>
|
|
int pwrapVMT(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
|
|
|
|
result = qp->ResultStorage(s);
|
|
MPointer* mp = (MPointer*) result.addr;
|
|
|
|
if((*mp)()){ // evaluate only once
|
|
return 0;
|
|
}
|
|
|
|
T* t = (T*) args[0].addr;
|
|
if(!t->IsDefined()){ // keep 0 pointer
|
|
return 0;
|
|
}
|
|
MemoryObject* ptr = catalog->getMMObject(t->GetValue());
|
|
mp->setPointer(ptr);
|
|
return 0;
|
|
}
|
|
|
|
int pwrapSelect(ListExpr args){
|
|
return CcString::checkType(nl->First(args))?0:1;
|
|
}
|
|
|
|
ValueMapping pwrapVM[] = {
|
|
pwrapVMT<CcString>,
|
|
pwrapVMT<Mem>
|
|
};
|
|
|
|
OperatorSpec pwrapSpec(
|
|
"{string, mem} -> mpointer",
|
|
"pwrap(_)",
|
|
"converts a name into a memory pointer",
|
|
"query pwrap(\"mten\")"
|
|
);
|
|
|
|
Operator pwrapOp(
|
|
"pwrap",
|
|
pwrapSpec.getStr(),
|
|
2,
|
|
pwrapVM,
|
|
pwrapSelect,
|
|
pwrapTM
|
|
);
|
|
|
|
/*
|
|
11 Variant of matchbelow
|
|
|
|
*/
|
|
|
|
ListExpr matchbelow2TM(ListExpr args){
|
|
|
|
if(!nl->HasLength(args,5)){
|
|
return listutils::typeError("wrong number of arguments, expected 5");
|
|
}
|
|
ListExpr tree = nl->First(args);
|
|
if(MPointer::checkType(tree)){
|
|
tree = nl->Second(tree);
|
|
}
|
|
if(!Mem::checkType(tree)){
|
|
return listutils::typeError("first arg is not of type mem or mpointer");
|
|
}
|
|
// remove mem from tree description
|
|
tree = nl->Second(tree);
|
|
if( !MemoryAVLObject::checkType(tree)
|
|
&& !MemoryTTreeObject::checkType(tree)){
|
|
return listutils::typeError("first arg must be a main memory "
|
|
"avl-tree or t-tree.");
|
|
}
|
|
|
|
bool isAVL = MemoryAVLObject::checkType(tree);
|
|
ListExpr treeType = nl->Second(tree);
|
|
|
|
ListExpr rel = nl->Second(args);
|
|
|
|
if(MPointer::checkType(rel)){
|
|
rel = nl->Second(rel); // remove mpointer
|
|
}
|
|
if(!Mem::checkType(rel)){
|
|
return listutils::typeError("second argument not of type mpointer or mem");
|
|
}
|
|
rel = nl->Second(rel); // remove mem
|
|
|
|
if(!Relation::checkType(rel)){
|
|
return listutils::typeError("Second arg is not a memory relation");
|
|
}
|
|
|
|
ListExpr searchType = nl->Third(args);
|
|
|
|
if(!nl->Equal(searchType,treeType)){
|
|
return listutils::typeError("search key type differs from tree type");
|
|
}
|
|
|
|
ListExpr attrName = nl->Fourth(args);
|
|
if(nl->AtomType(attrName)!=SymbolType){
|
|
return listutils::typeError("fourth arg must be an attribute name");
|
|
}
|
|
string aname = nl->SymbolValue(attrName);
|
|
ListExpr attrType;
|
|
ListExpr attrList = nl->Second(nl->Second(rel));
|
|
int index = listutils::findAttribute(attrList,aname,attrType);
|
|
if(!index){
|
|
return listutils::typeError("attribute " + aname
|
|
+ " not found in relation");
|
|
}
|
|
ListExpr defaultType = nl->Fifth(args);
|
|
if(!nl->Equal(attrType,defaultType)){
|
|
return listutils::typeError("default value type differs "
|
|
"from attribute type");
|
|
}
|
|
return nl->ThreeElemList(
|
|
nl->SymbolAtom(Symbols::APPEND()),
|
|
nl->TwoElemList(nl->BoolAtom(isAVL),
|
|
nl->IntAtom(index-1)),
|
|
defaultType
|
|
);
|
|
}
|
|
|
|
|
|
template<class T, class R>
|
|
int matchbelow2VMT(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
|
|
result = qp->ResultStorage(s);
|
|
Attribute* res = (Attribute*) result.addr;
|
|
|
|
R* relN = (R*) args[1].addr;
|
|
MemoryRelObject* mro = getMemRel(relN);
|
|
if(!mro){
|
|
res->SetDefined(false);
|
|
return 0;
|
|
}
|
|
|
|
vector<Tuple*>* rel = mro->getmmrel();
|
|
size_t size = rel->size();
|
|
T* treeN = (T*) args[0].addr;
|
|
bool isAVL = ((CcBool*) args[5].addr)->GetValue();
|
|
|
|
Attribute* searchValue = (Attribute*) args[2].addr;
|
|
Attribute* defaultValue = (Attribute*) args[4].addr;
|
|
int attrIndex = ((CcInt*)args[6].addr)->GetValue();
|
|
AttrIdPair const* hit=0;
|
|
|
|
AttrIdPair p(searchValue,size);
|
|
if(isAVL){
|
|
memAVLtree* tree = getAVLtree(treeN);
|
|
if(!tree){
|
|
res->SetDefined(0);
|
|
return 0;
|
|
}
|
|
hit = tree->GetNearestSmallerOrEqual(p);
|
|
} else {
|
|
MemoryTTreeObject* tree = getTtree(treeN);
|
|
if(!tree){
|
|
res->SetDefined(0);
|
|
return 0;
|
|
}
|
|
hit = tree->gettree()->GetNearestSmallerOrEqual(p,0);
|
|
}
|
|
if(!hit){ // tree empty or searchvalue smaller than all entries
|
|
res->CopyFrom(defaultValue);
|
|
return 0;
|
|
}
|
|
TupleId tid = hit->getTid();
|
|
if(tid>size || tid<1){
|
|
res->SetDefined(false);
|
|
return 0;
|
|
}
|
|
Tuple* rt = rel->at(tid-1);
|
|
if(!rt){ // deleted tuple
|
|
res->SetDefined(false);
|
|
return 0;
|
|
}
|
|
res->CopyFrom(rt->GetAttribute(attrIndex));
|
|
|
|
return 0;
|
|
}
|
|
|
|
ValueMapping matchbelow2VM[] = {
|
|
matchbelow2VMT<Mem,Mem>,
|
|
matchbelow2VMT<Mem,MPointer>,
|
|
matchbelow2VMT<MPointer,Mem>,
|
|
matchbelow2VMT<MPointer,MPointer>
|
|
};
|
|
|
|
int matchbelow2Select(ListExpr args){
|
|
ListExpr tree = nl->First(args);
|
|
int n1 = Mem::checkType(tree)?0 : 2;
|
|
|
|
ListExpr rel = nl->Second(args);
|
|
int n2 = Mem::checkType(rel)?0:1;
|
|
return n1+n2;
|
|
}
|
|
|
|
OperatorSpec matchbelow2Spec(
|
|
"{AVLTREE, TTREE} x MREL x T x Ident x V -> V , "
|
|
"AVLTREE, TTREE, MREL in {string, mem, mpointer}",
|
|
"tree rel matchbelow2[searchV, attrName, defaultV]",
|
|
"Retrieves from an avl tree the entry which is "
|
|
"less or equal to searchV. From the returned tuple id, "
|
|
"the tuple in the relation is retrieved and the "
|
|
"attribute with given name is extracted. "
|
|
"If the avl tree does not returns a hit, the defaultV is "
|
|
"used as the result. If the tuple id is not present in the "
|
|
"relation, the result is undefined. ",
|
|
"query avl rel matchbelow2[ 23, Name, \"Unknown\"] "
|
|
);
|
|
|
|
|
|
Operator matchbelow2Op(
|
|
"matchbelow2",
|
|
matchbelow2Spec.getStr(),
|
|
4,
|
|
matchbelow2VM,
|
|
matchbelow2Select,
|
|
matchbelow2TM
|
|
);
|
|
|
|
|
|
/*
|
|
12 Operator count
|
|
|
|
*/
|
|
ListExpr countTM(ListExpr args){
|
|
if(!nl->HasLength(args,1)){
|
|
return listutils::typeError("one arg expected");
|
|
}
|
|
ListExpr a1 = nl->First(args);
|
|
if(MPointer::checkType(a1)){
|
|
a1 = nl->Second(a1);
|
|
}
|
|
if(!Mem::checkType(a1)){
|
|
return listutils::typeError("arg not of type mpointer or mem");
|
|
}
|
|
a1 = nl->Second(a1); // remove leading mem
|
|
if( !Relation::checkType(a1)
|
|
&& !OrderedRelation::checkType(a1)){
|
|
return listutils::typeError("not a memory (o)rel");
|
|
}
|
|
return listutils::basicSymbol<CcInt>();
|
|
}
|
|
|
|
|
|
int countVMMem(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
|
|
Mem* arg = (Mem*)args[0].addr;
|
|
result = qp->ResultStorage(s);
|
|
CcInt* res = (CcInt*) result.addr;
|
|
if(!arg->IsDefined()){
|
|
res->SetDefined(false);
|
|
return 0;
|
|
}
|
|
string name = arg->GetValue();
|
|
if(!catalog->isObject(name) ) {
|
|
res->SetDefined(false);
|
|
return 0;
|
|
}
|
|
ListExpr relType = nl->Second(catalog->getMMObjectTypeExpr(name));
|
|
|
|
if(Relation::checkType(relType)){
|
|
res->Set(true, ((MemoryRelObject*)catalog->getMMObject(name))->getSize());
|
|
} else if(OrderedRelation::checkType(relType)){
|
|
res->Set(true,((MemoryORelObject*)catalog->getMMObject(name))->getSize());
|
|
} else {
|
|
res->SetDefined(false);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
template<class RelType>
|
|
int countVMMPointer(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
MPointer* arg = (MPointer*) args[0].addr;
|
|
RelType* rel = (RelType*) arg->GetValue();
|
|
int c = rel?rel->getSize():0;
|
|
result = qp->ResultStorage(s);
|
|
((CcInt*) result.addr)->Set(true,c);
|
|
return 0;
|
|
}
|
|
|
|
|
|
ValueMapping countVM[] = {
|
|
countVMMem,
|
|
countVMMPointer<MemoryRelObject>,
|
|
countVMMPointer<MemoryORelObject>
|
|
};
|
|
|
|
int countSelect(ListExpr args){
|
|
ListExpr a1 = nl->First(args);
|
|
if(Mem::checkType(a1)) return 0;
|
|
// an mpointer
|
|
a1 = nl->Second(nl->Second(a1));
|
|
return Relation::checkType(a1)?1:2;
|
|
}
|
|
|
|
OperatorSpec countSpec(
|
|
" {MREL, MOREL} -> int",
|
|
"_ count",
|
|
"returns the size of an (ordered) memory relation",
|
|
" query mten count"
|
|
);
|
|
|
|
Operator countOp(
|
|
"count",
|
|
countSpec.getStr(),
|
|
3,
|
|
countVM,
|
|
countSelect,
|
|
countTM
|
|
);
|
|
|
|
|
|
|
|
/*
|
|
8 Operators on priority queues
|
|
|
|
8.1 mcreatepqueue
|
|
|
|
Creates a new priority queue in main memory.
|
|
|
|
stream(tuple) x AttrName -> mpointer(mem(mpqueue(tuple)))
|
|
|
|
*/
|
|
ListExpr mcreatepqueueTM(ListExpr args){
|
|
|
|
if(!nl->HasLength(args,2)){
|
|
return listutils::typeError("two arguments expected");
|
|
}
|
|
if(!Stream<Tuple>::checkType(nl->First(args))){
|
|
return listutils::typeError("first arg is not a tuple stream");
|
|
}
|
|
if(nl->AtomType(nl->Second(args))!=SymbolType){
|
|
return listutils::typeError("second arg is not a valid identifier");
|
|
}
|
|
ListExpr tupleType = nl->Second(nl->First(args));
|
|
ListExpr attrList = nl->Second(tupleType);
|
|
string attrName = nl->SymbolValue(nl->Second(args));
|
|
ListExpr attrType;
|
|
int index = listutils::findAttribute(attrList, attrName, attrType);
|
|
if(!index){
|
|
return listutils::typeError(attrName + " is not a member of the tuple");
|
|
}
|
|
if(!CcReal::checkType(attrType)){
|
|
return listutils::typeError("Attribute " + attrName + " not of type real");
|
|
}
|
|
ListExpr res = MPointer::wrapType(Mem::wrapType(
|
|
MemoryPQueueObject::wrapType(tupleType)));
|
|
|
|
return nl->ThreeElemList( nl->SymbolAtom(Symbols::APPEND()),
|
|
nl->OneElemList(nl->IntAtom(index-1)),
|
|
res);
|
|
}
|
|
|
|
|
|
template<bool flob>
|
|
int mcreatepqueueVM(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
result = qp->ResultStorage(s);
|
|
MPointer* mp = (MPointer*) result.addr;
|
|
string dbname = getDBname();
|
|
ListExpr tt = nl->Second(nl->Second(nl->Second(qp->GetType(s))));
|
|
ListExpr type = Mem::wrapType(MemoryPQueueObject::wrapType(tt));
|
|
int prioIndex = ((CcInt*) args[2].addr)->GetValue();
|
|
MemoryPQueueObject* q = new MemoryPQueueObject(flob, dbname,
|
|
nl->ToString(type));
|
|
Stream<Tuple> stream(args[0]);
|
|
stream.open();
|
|
Tuple* tuple;
|
|
while( (tuple= stream.request())){
|
|
CcReal* prio = (CcReal*) tuple->GetAttribute(prioIndex);
|
|
if(prio->IsDefined()){
|
|
q->push(tuple, prio->GetValue());
|
|
}
|
|
tuple->DeleteIfAllowed();
|
|
}
|
|
stream.close();
|
|
mp->setPointer(q);
|
|
q->deleteIfAllowed();
|
|
return 0;
|
|
}
|
|
|
|
|
|
OperatorSpec mcreatepqueueSpec(
|
|
"stream(tuple) x IDENT -> mpointer(mem(pqueue)) ",
|
|
"_ mcreatepqueue[_]",
|
|
"Creates a priority in memory storing the "
|
|
" tuples of the stream. The priority comes from the "
|
|
"attribute that's name is given in the second argument. "
|
|
"This attribute has to be of type real. "
|
|
"If this attribute is undefined, the values are not inserted "
|
|
"into the queue but nevertheless part of the output stream.",
|
|
"query strassen extend[L : size(.GeoData)] mcreatepqueue[L] count"
|
|
|
|
);
|
|
|
|
Operator mcreatepqueueOp(
|
|
"mcreatepqueue",
|
|
mcreatepqueueSpec.getStr(),
|
|
mcreatepqueueVM<false>,
|
|
Operator::SimpleSelect,
|
|
mcreatepqueueTM
|
|
);
|
|
|
|
Operator mcreatepqueueflobOp(
|
|
"mcreatepqueueflob",
|
|
mcreatepqueueSpec.getStr(),
|
|
mcreatepqueueVM<true>,
|
|
Operator::SimpleSelect,
|
|
mcreatepqueueTM
|
|
);
|
|
|
|
|
|
|
|
template<class T>
|
|
ListExpr sizeTM( ListExpr args){
|
|
if(!nl->HasLength(args,1)){
|
|
return listutils::typeError("one argument expected");
|
|
}
|
|
ListExpr a1;
|
|
if(!getMemSubType(nl->First(args),a1)){
|
|
return listutils::typeError("first arg is not a memory object");
|
|
}
|
|
if(!T::checkType(a1)){
|
|
return listutils::typeError("argument is not of type " + T::BasicType());
|
|
}
|
|
return listutils::basicSymbol<CcInt>();
|
|
}
|
|
|
|
|
|
template<class T, class C>
|
|
int sizeVMT(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
result = qp->ResultStorage(s);
|
|
CcInt* res = (CcInt*) result.addr;
|
|
C* q = getMemObject<C>((T*) args[0].addr);
|
|
if(!q){
|
|
res->SetDefined(false);
|
|
} else {
|
|
res->Set(true, q->size());
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
ValueMapping sizeVM[] = {
|
|
sizeVMT<Mem, MemoryPQueueObject>,
|
|
sizeVMT<MPointer, MemoryPQueueObject>,
|
|
};
|
|
|
|
int sizeSelect(ListExpr args){
|
|
ListExpr a = nl->First(args);
|
|
if(Mem::checkType(a)) return 0;
|
|
if(MPointer::checkType(a)) return 1;
|
|
return -1;
|
|
}
|
|
|
|
|
|
OperatorSpec sizeSpec(
|
|
"mpqueue -> int",
|
|
"size(_)",
|
|
"Returns the number of entries in an mpqueue.",
|
|
"query size(strassen_L)"
|
|
);
|
|
|
|
Operator sizeOp(
|
|
"size",
|
|
sizeSpec.getStr(),
|
|
2,
|
|
sizeVM,
|
|
sizeSelect,
|
|
sizeTM<MemoryPQueueObject>
|
|
);
|
|
|
|
|
|
/*
|
|
Operator mfeedpq
|
|
|
|
*/
|
|
ListExpr mfeedpqTM(ListExpr args){
|
|
if(!nl->HasLength(args,1)){
|
|
return listutils::typeError("one argument expected");
|
|
}
|
|
ListExpr a1;
|
|
if(!getMemSubType(nl->First(args),a1)){
|
|
return listutils::typeError("argument is not a memory object");
|
|
}
|
|
if(!MemoryPQueueObject::checkType(a1)){
|
|
return listutils::typeError("expected mpqueue");
|
|
}
|
|
return nl->TwoElemList(
|
|
listutils::basicSymbol<Stream<Tuple> >(),
|
|
nl->Second(a1));
|
|
|
|
}
|
|
|
|
class mfeedpqInfo{
|
|
public:
|
|
mfeedpqInfo(MemoryPQueueObject* _obj): obj(_obj),minSize(0){}
|
|
mfeedpqInfo(MemoryPQueueObject* _obj,
|
|
int _minSize): obj(_obj),minSize(_minSize){}
|
|
|
|
~mfeedpqInfo(){}
|
|
|
|
Tuple* next(){
|
|
if(obj->empty()){
|
|
return 0;
|
|
}
|
|
pqueueentry e = obj->pop();
|
|
Tuple* t = e();
|
|
return t;
|
|
}
|
|
|
|
Tuple* nextMinSize(){
|
|
if(obj->empty() || obj->size()<=minSize){
|
|
return 0;
|
|
}
|
|
pqueueentry e = obj->pop();
|
|
Tuple* t = e();
|
|
return t;
|
|
}
|
|
|
|
|
|
private:
|
|
MemoryPQueueObject* obj;
|
|
size_t minSize;
|
|
};
|
|
|
|
|
|
template<class T>
|
|
int mfeedpqVMT(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
|
|
mfeedpqInfo* li = (mfeedpqInfo*) local.addr;
|
|
switch(message){
|
|
case OPEN:{
|
|
if(li){
|
|
delete li;
|
|
local.addr = 0;
|
|
}
|
|
MemoryPQueueObject* q = getMemoryPQueue((T*) args[0].addr);
|
|
if(q){
|
|
local.addr = new mfeedpqInfo(q);
|
|
}
|
|
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;
|
|
}
|
|
|
|
ValueMapping mfeedpqVM[] = {
|
|
mfeedpqVMT<Mem>,
|
|
mfeedpqVMT<MPointer>
|
|
};
|
|
|
|
int mfeedpqSelect(ListExpr args){
|
|
ListExpr a = nl->First(args);
|
|
if(Mem::checkType(a)) return 0;
|
|
if(MPointer::checkType(a)) return 1;
|
|
return -1;
|
|
}
|
|
|
|
|
|
OperatorSpec mfeedpqSpec(
|
|
"MPQUEUE -> stream(tuple)",
|
|
" _ mfeedpq ",
|
|
"Feeds the constent of a priority queue into a tuple stream. "
|
|
"In contrast to a 'normal' feed, the queue is eat up.",
|
|
"query strassen_L mfeedpq count"
|
|
);
|
|
|
|
|
|
Operator mfeedpqOp(
|
|
"mfeedpq",
|
|
mfeedpqSpec.getStr(),
|
|
2,
|
|
mfeedpqVM,
|
|
mfeedpqSelect,
|
|
mfeedpqTM
|
|
);
|
|
|
|
|
|
/*
|
|
Operator mfeedpqSize
|
|
|
|
*/
|
|
ListExpr mfeedpqSizeTM(ListExpr args){
|
|
if(!nl->HasLength(args,2)){
|
|
return listutils::typeError("two arguments expected");
|
|
}
|
|
ListExpr a1;
|
|
if(!getMemSubType(nl->First(args),a1)){
|
|
return listutils::typeError("first arg is not a memory object");
|
|
}
|
|
if(!MemoryPQueueObject::checkType(a1)){
|
|
return listutils::typeError("expected mpqueue");
|
|
}
|
|
if(!CcInt::checkType(nl->Second(args))){
|
|
return listutils::typeError("expected int as second argument");
|
|
}
|
|
|
|
return nl->TwoElemList(
|
|
listutils::basicSymbol<Stream<Tuple> >(),
|
|
nl->Second(a1));
|
|
|
|
}
|
|
|
|
template<class T>
|
|
int mfeedpqSizeVMT(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
|
|
mfeedpqInfo* li = (mfeedpqInfo*) local.addr;
|
|
switch(message){
|
|
case OPEN:{
|
|
if(li){
|
|
delete li;
|
|
local.addr = 0;
|
|
}
|
|
MemoryPQueueObject* q = getMemoryPQueue((T*) args[0].addr);
|
|
if(q){
|
|
int s = 0;
|
|
CcInt* S = (CcInt*) args[1].addr;
|
|
if(S->IsDefined()){
|
|
s = S->GetValue();
|
|
if(s<0) s = 0;
|
|
}
|
|
local.addr = new mfeedpqInfo(q,s);
|
|
}
|
|
return 0;
|
|
}
|
|
case REQUEST:
|
|
result.addr = li?li->nextMinSize():0;
|
|
return result.addr?YIELD:CANCEL;
|
|
case CLOSE:
|
|
if(li){
|
|
delete li;
|
|
local.addr = 0;
|
|
}
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
ValueMapping mfeedpqSizeVM[] = {
|
|
mfeedpqSizeVMT<Mem>,
|
|
mfeedpqSizeVMT<MPointer>
|
|
};
|
|
|
|
int mfeedpqSizeSelect(ListExpr args){
|
|
ListExpr a = nl->First(args);
|
|
if(Mem::checkType(a)) return 0;
|
|
if(MPointer::checkType(a)) return 1;
|
|
return -1;
|
|
}
|
|
|
|
|
|
OperatorSpec mfeedpqSizeSpec(
|
|
"MPQUEUE x int -> stream(tuple)",
|
|
" _ mfeedpq ",
|
|
"Feeds the content of a priority queue into a tuple stream "
|
|
"until the queue is empty or a minimum size of the queue "
|
|
"is reached."
|
|
"In contrast to a 'normal' feed, the queue is eat up.",
|
|
"query strassen_L mfeedpqSize[2] count"
|
|
);
|
|
|
|
|
|
Operator mfeedpqSizeOp(
|
|
"mfeedpqSize",
|
|
mfeedpqSizeSpec.getStr(),
|
|
2,
|
|
mfeedpqSizeVM,
|
|
mfeedpqSizeSelect,
|
|
mfeedpqSizeTM
|
|
);
|
|
|
|
|
|
|
|
/*
|
|
Operator mfeedpqAbort
|
|
|
|
*/
|
|
ListExpr mfeedpqAbortTM(ListExpr args){
|
|
if(!nl->HasLength(args,2)){
|
|
return listutils::typeError("one argument expected");
|
|
}
|
|
ListExpr a1;
|
|
if(!getMemSubType(nl->First(args),a1)){
|
|
return listutils::typeError("first argument ist not a memory object");
|
|
}
|
|
if(!MemoryPQueueObject::checkType(a1)){
|
|
return listutils::typeError("expected mpqueue");
|
|
}
|
|
ListExpr max = nl->Second(args);
|
|
if( !CcReal::checkType(max)
|
|
&& !CcInt::checkType(max)){
|
|
return listutils::typeError("The second argument must be of "
|
|
"type int or real");
|
|
}
|
|
return nl->TwoElemList(
|
|
listutils::basicSymbol<Stream<Tuple> >(),
|
|
nl->Second(a1));
|
|
|
|
}
|
|
|
|
class mfeedpqAbortInfo{
|
|
public:
|
|
mfeedpqAbortInfo(MemoryPQueueObject* _obj, double _m): obj(_obj), m(_m){}
|
|
|
|
~mfeedpqAbortInfo(){}
|
|
|
|
Tuple* next(){
|
|
if(obj->empty()){
|
|
return 0;
|
|
}
|
|
if(obj->top().getPrio()>=m){ // maximum prio reached
|
|
return 0;
|
|
}
|
|
pqueueentry e = obj->pop();
|
|
Tuple* t = e();
|
|
return t;
|
|
}
|
|
|
|
private:
|
|
MemoryPQueueObject* obj;
|
|
double m;
|
|
};
|
|
|
|
|
|
template<class T, class M>
|
|
int mfeedpqAbortVMT(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
|
|
mfeedpqAbortInfo* li = (mfeedpqAbortInfo*) local.addr;
|
|
switch(message){
|
|
case OPEN:{
|
|
if(li){
|
|
delete li;
|
|
local.addr = 0;
|
|
}
|
|
MemoryPQueueObject* q = getMemoryPQueue((T*) args[0].addr);
|
|
M* max = (M*) args[1].addr;
|
|
if(!max->IsDefined()){
|
|
return 0;
|
|
}
|
|
if(q){
|
|
local.addr = new mfeedpqAbortInfo(q, max->GetValue());
|
|
}
|
|
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;
|
|
}
|
|
|
|
ValueMapping mfeedpqAbortVM[] = {
|
|
mfeedpqAbortVMT<Mem,CcInt>,
|
|
mfeedpqAbortVMT<Mem,CcReal>,
|
|
mfeedpqAbortVMT<MPointer,CcInt>,
|
|
mfeedpqAbortVMT<MPointer,CcReal>,
|
|
};
|
|
|
|
int mfeedpqAbortSelect(ListExpr args){
|
|
int n1 = Mem::checkType(nl->First(args))?0:2;
|
|
int n2 = CcInt::checkType(nl->Second(args))?0:1;
|
|
return n1 + n2;
|
|
}
|
|
|
|
|
|
OperatorSpec mfeedpqAbortSpec(
|
|
"MPQUEUE x {int,real} -> stream(tuple)",
|
|
" _ mfeedpqAbort[_] ",
|
|
"Feeds the constent of a priority queue into a tuple stream. "
|
|
"In contrast to a 'normal' feed, the queue is eat up. If "
|
|
"the maximum priority (2nd arg) ist reached, feeding is stopped",
|
|
"query strassen_L mfeedpqAbort[230.0] count"
|
|
);
|
|
|
|
|
|
Operator mfeedpqAbortOp(
|
|
"mfeedpqAbort",
|
|
mfeedpqAbortSpec.getStr(),
|
|
4,
|
|
mfeedpqAbortVM,
|
|
mfeedpqAbortSelect,
|
|
mfeedpqAbortTM
|
|
);
|
|
|
|
|
|
/*
|
|
Operator ~minsertTuplepq~
|
|
|
|
*/
|
|
|
|
ListExpr minsertTuplepq(ListExpr args){
|
|
if(!nl->HasLength(args,3) && !nl->HasLength(args,4)){
|
|
return listutils::typeError("3 or 4 arguments expected");
|
|
}
|
|
ListExpr a1;
|
|
if(!getMemSubType(nl->First(args),a1)){
|
|
return listutils::typeError("first argument is not a memory object");
|
|
}
|
|
if(!MemoryPQueueObject::checkType(a1)){
|
|
return listutils::typeError("first arg is not a mpqueue");
|
|
}
|
|
|
|
|
|
ListExpr tuple = nl->Second(args);
|
|
if(!Tuple::checkType(tuple)){
|
|
return listutils::typeError("second arg is not a tuple");
|
|
}
|
|
if(!nl->Equal(nl->Second(a1), tuple)){
|
|
return listutils::typeError("tuple type does not fit the tuple "
|
|
"stored in queue");
|
|
}
|
|
|
|
if(!CcReal::checkType(nl->Third(args))){
|
|
return listutils::typeError("third arg is not a real");
|
|
}
|
|
if(nl->HasLength(args,3)){
|
|
return listutils::basicSymbol<CcBool>();
|
|
}
|
|
ListExpr attrName = nl->Fourth(args);
|
|
if(!listutils::isSymbol(attrName)){
|
|
return listutils::typeError("4th arg is not a valid attribute name");
|
|
}
|
|
string an = nl->SymbolValue(attrName);
|
|
ListExpr attrType;
|
|
ListExpr attrList = nl->Second(tuple);
|
|
int index = listutils::findAttribute(attrList,an,attrType);
|
|
if(!index){
|
|
return listutils::typeError("attribute " + an + "not part of the tuple");
|
|
}
|
|
if(!CcReal::checkType(attrType)){
|
|
return listutils::typeError("attribute " + an + " of type real");
|
|
}
|
|
return nl->ThreeElemList(
|
|
nl->SymbolAtom(Symbols::APPEND()),
|
|
nl->OneElemList(nl->IntAtom(index-1)),
|
|
listutils::basicSymbol<CcBool>());
|
|
}
|
|
|
|
template<class T>
|
|
int minserttuplepqVMT(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
|
|
result = qp->ResultStorage(s);
|
|
CcBool* res = (CcBool*) result.addr;
|
|
|
|
MemoryPQueueObject* q = getMemoryPQueue((T*) args[0].addr);
|
|
if(!q){
|
|
res->SetDefined(false);
|
|
return 0;
|
|
}
|
|
Tuple* tuple = (Tuple*) args[1].addr;
|
|
CcReal* prioS = (CcReal*) args[2].addr;
|
|
if(!prioS->IsDefined()){
|
|
res->SetDefined(false);
|
|
return 0;
|
|
}
|
|
double prio = prioS->GetValue();
|
|
if(qp->GetNoSons(s)>4){ // update tuple entry if desired
|
|
int prioIndex = ((CcInt*) args[4].addr)->GetValue();
|
|
((CcReal*) tuple->GetAttribute(prioIndex))->Set(true,prio);
|
|
}
|
|
q->push(tuple,prio);
|
|
res->Set(true,true);
|
|
return 0;
|
|
}
|
|
|
|
|
|
ValueMapping minsertTuplepqVM[] = {
|
|
minserttuplepqVMT<Mem>,
|
|
minserttuplepqVMT<MPointer>
|
|
};
|
|
|
|
int minsertTuplepqSelect(ListExpr args){
|
|
ListExpr a = nl->First(args);
|
|
if(Mem::checkType(a)) return 0;
|
|
if(MPointer::checkType(a)) return 1;
|
|
return -1;
|
|
}
|
|
|
|
OperatorSpec minsertTupleSpec(
|
|
"MPQUEUE x tuple x real [x IDENT] -> bool",
|
|
"minserttuplepq(_,_,_,_)",
|
|
"Inserts a tuple into a memory priority queue with a "
|
|
"given priority. If the optional attribute name is given, "
|
|
"the specified attribute of the tuple is changed to the "
|
|
"priority value before insertion. Of course the attribute "
|
|
"has to be of type real.",
|
|
"query strassen feed extend[L : size(.GeoData)] "
|
|
"extend[ Ok : minserttuplepq(mstrassen_PQ_L, . , .L * 2.0,L)] "
|
|
" count");
|
|
|
|
|
|
Operator minsertTuplepqOp(
|
|
"minserttuplepq",
|
|
minsertTupleSpec.getStr(),
|
|
2,
|
|
minsertTuplepqVM,
|
|
minsertTuplepqSelect,
|
|
minsertTuplepq
|
|
);
|
|
|
|
|
|
|
|
/*
|
|
Operator ~minsertTuplepqProject~
|
|
|
|
This operator works similar to minsertTuplepq but allowes to
|
|
project the incoming tuple to a set of attributes before insertion.
|
|
|
|
Type Mapping
|
|
|
|
queue tuple real [IDENT] <list of IDENT>
|
|
|
|
*/
|
|
|
|
ListExpr minserttuplepqprojectTM(ListExpr args){
|
|
if(!nl->HasLength(args,4) && !nl->HasLength(args,5)){
|
|
return listutils::typeError("4 or 5 arguments required");
|
|
}
|
|
ListExpr a1;
|
|
if(!getMemSubType(nl->First(args),a1)){
|
|
return listutils::typeError("first argument is not a memory object");
|
|
}
|
|
if(!MemoryPQueueObject::checkType(a1)){
|
|
return listutils::typeError("first arg is not a mpqueue");
|
|
}
|
|
|
|
ListExpr tuple = nl->Second(args);
|
|
if(!Tuple::checkType(tuple)){
|
|
return listutils::typeError("second arg is not a tuple");
|
|
}
|
|
|
|
|
|
ListExpr prio = nl->Third(args);
|
|
if(!CcReal::checkType(prio)){
|
|
return listutils::typeError("third arg is not a real");
|
|
}
|
|
|
|
ListExpr projectList;
|
|
string updateAttr = "";
|
|
ListExpr attrList = nl->Second(tuple);
|
|
int updateIndex = -1;
|
|
|
|
if(nl->HasLength(args,4)){
|
|
projectList = nl->Fourth(args);
|
|
} else {
|
|
projectList = nl->Fifth(args);
|
|
ListExpr update = nl->Fourth(args);
|
|
if(!listutils::isSymbol(update)){
|
|
return listutils::typeError("fourth arg is not a valid attribute name");
|
|
}
|
|
updateAttr = nl->SymbolValue(update);
|
|
ListExpr attrType;
|
|
updateIndex = listutils::findAttribute(attrList,updateAttr,attrType);
|
|
if(!updateIndex){
|
|
return listutils::typeError("Attribute name " + updateAttr
|
|
+ " not part of the tuple");
|
|
}
|
|
if(!CcReal::checkType(attrType)){
|
|
return listutils::typeError("attribute " + updateAttr
|
|
+ " not of type real");
|
|
}
|
|
}
|
|
|
|
if(nl->AtomType(projectList)!=NoAtom){
|
|
return listutils::typeError("last argument must be a list "
|
|
"of attribute names");
|
|
}
|
|
set<string> project;
|
|
int updatePos = -1;
|
|
ListExpr resAttrList = nl->TheEmptyList();
|
|
ListExpr lastAttrList = nl->TheEmptyList();
|
|
ListExpr projectPos = nl->TheEmptyList();
|
|
ListExpr lastProjectPos=nl->TheEmptyList();
|
|
bool first = true;
|
|
int pos = 0;
|
|
|
|
while(!nl->IsEmpty(projectList)){
|
|
ListExpr attr = nl->First(projectList);
|
|
projectList = nl->Rest(projectList);
|
|
|
|
if(!listutils::isSymbol(attr)){
|
|
return listutils::typeError("projection list contains invalid "
|
|
"attribute name");
|
|
}
|
|
string attrName = nl->SymbolValue(attr);
|
|
if(attrName == updateAttr){
|
|
updatePos = pos;
|
|
}
|
|
pos++;
|
|
if(project.find(attrName)!=project.end()){
|
|
return listutils::typeError( "attribute name " + attrName
|
|
+ " found twice in projection list");
|
|
}
|
|
|
|
project.insert(attrName);
|
|
|
|
|
|
ListExpr attrType;
|
|
int index = listutils::findAttribute(attrList, attrName, attrType);
|
|
if(!index){
|
|
return listutils::typeError( "attribute " + attrName
|
|
+ " not part of the tuple");
|
|
}
|
|
|
|
// attrname is ok
|
|
if(first){
|
|
first = false;
|
|
resAttrList = nl->OneElemList(nl->TwoElemList(attr, attrType));
|
|
lastAttrList = resAttrList;
|
|
projectPos = nl->OneElemList( nl->IntAtom(index-1));
|
|
lastProjectPos = projectPos;
|
|
} else {
|
|
lastAttrList = nl->Append(lastAttrList,
|
|
nl->TwoElemList(attr, attrType));
|
|
lastProjectPos = nl->Append(lastProjectPos, nl->IntAtom(index-1));
|
|
}
|
|
|
|
}
|
|
|
|
|
|
if( (updateAttr!="") && (updatePos<0)){
|
|
return listutils::typeError("update attribute not part of "
|
|
"projection list");
|
|
}
|
|
|
|
if(updatePos>=0){
|
|
lastProjectPos = nl->Append(lastProjectPos, nl->IntAtom(updatePos));
|
|
}
|
|
|
|
ListExpr queueAttrList = nl->Second(nl->Second(a1));
|
|
if(!nl->Equal(resAttrList,queueAttrList)){
|
|
return listutils::typeError("projected tuples does not fit the "
|
|
"queue tuple type");
|
|
}
|
|
|
|
ListExpr res = nl->ThreeElemList(
|
|
nl->SymbolAtom(Symbols::APPEND()),
|
|
projectPos,
|
|
listutils::basicSymbol<CcBool>());
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
template<class T, bool update>
|
|
int minserttuplepqprojectVMT(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
|
|
result = qp->ResultStorage(s);
|
|
CcBool* res = (CcBool*) result.addr;
|
|
|
|
MemoryPQueueObject* q = getMemoryPQueue((T*) args[0].addr);
|
|
if(!q){
|
|
res->SetDefined(false);
|
|
return 0;
|
|
}
|
|
Tuple* tuple = (Tuple*) args[1].addr;
|
|
CcReal* prioS = (CcReal*) args[2].addr;
|
|
if(!prioS->IsDefined()){
|
|
res->SetDefined(false);
|
|
return 0;
|
|
}
|
|
double prio = prioS->GetValue();
|
|
TupleType* tt = q->getTupleType();
|
|
assert(tt);
|
|
|
|
int min, max, updatePos;
|
|
if(update){
|
|
min = 5;
|
|
max = qp->GetNoSons(s) -1;
|
|
updatePos = ((CcInt*) args[max].addr)->GetValue();
|
|
} else {
|
|
min = 4;
|
|
max = qp->GetNoSons(s);
|
|
updatePos = -1;
|
|
}
|
|
|
|
Tuple* insertTuple = new Tuple(tt);
|
|
for(int i=min;i<max;i++){
|
|
int p = ((CcInt*) args[i].addr)->GetValue();
|
|
if(p!=updatePos){
|
|
insertTuple->CopyAttribute(p,tuple,i-min);
|
|
} else {
|
|
insertTuple->PutAttribute(i-min, new CcReal(true,prio));
|
|
}
|
|
}
|
|
|
|
q->push(insertTuple,prio);
|
|
insertTuple->DeleteIfAllowed();
|
|
res->Set(true,true);
|
|
return 0;
|
|
}
|
|
|
|
|
|
ValueMapping minserttuplepqprojectVM[] = {
|
|
minserttuplepqprojectVMT<Mem,false>,
|
|
minserttuplepqprojectVMT<Mem,true>,
|
|
minserttuplepqprojectVMT<MPointer,false>,
|
|
minserttuplepqprojectVMT<MPointer,true>
|
|
};
|
|
|
|
int minserttuplepqprojectSelect(ListExpr args){
|
|
int n1 = Mem::checkType(nl->First(args))?0:2;
|
|
int n2 = nl->HasLength(args,4)?0:1;
|
|
return n1+n2;
|
|
}
|
|
|
|
OperatorSpec minserttuplepqprojectUSpec(
|
|
"mpqueue x tuple x real x IDENT x <IDENTLIST> -> bool, "
|
|
"mpqueue in {mem, mpointer",
|
|
"minserttuplepqproject(_,_,_,_;list)",
|
|
"projects a tuple to the attributes enumerated in the identifier list "
|
|
"with a specified priority into a main memory priority queue. "
|
|
"The attribute in the tuple specified by the 4th argument, "
|
|
"is updated to the value of the priority before inserting"
|
|
" the projected tuple into the queue.",
|
|
"query strassen feed extend[L : size(.GeoData), K : 1.0] "
|
|
"extend[ Ok : mstrassen_PQ_L "
|
|
"minserttuplepqprojectU[ . , .L * 2.0, L;Name,Typ,GeoData,L]] count"
|
|
);
|
|
|
|
Operator minserttuplepqprojectUOp(
|
|
"minserttuplepqprojectU",
|
|
minserttuplepqprojectUSpec.getStr(),
|
|
4,
|
|
minserttuplepqprojectVM,
|
|
minserttuplepqprojectSelect,
|
|
minserttuplepqprojectTM
|
|
);
|
|
|
|
|
|
OperatorSpec minserttuplepqprojectSpec(
|
|
"mpqueue x tuple x real x <IDENTLIST> -> bool "
|
|
"mpqueue in { mem, mpointer",
|
|
"minserttuplepqproject(_,_,_,_;list)",
|
|
"projects a tuple to the attributes enumerated in the identifier list "
|
|
"with a specified priority into a main memory priority queue. ",
|
|
"query strassen feed extend[L : size(.GeoData), K : 1.0] "
|
|
"extend[ Ok : mstrassen_PQ_L "
|
|
"minserttuplepqproject[ . , .L * 2.0;Name,Typ,GeoData,L]] count"
|
|
);
|
|
|
|
Operator minserttuplepqprojectOp(
|
|
"minserttuplepqproject",
|
|
minserttuplepqprojectSpec.getStr(),
|
|
4,
|
|
minserttuplepqprojectVM,
|
|
minserttuplepqprojectSelect,
|
|
minserttuplepqprojectTM
|
|
);
|
|
|
|
|
|
|
|
|
|
/*
|
|
8.8 mpwreorder
|
|
|
|
*/
|
|
template<int numArgs>
|
|
ListExpr mpqreorderTM(ListExpr args){
|
|
|
|
// mpqueue x fun [x AttrName]
|
|
if(!nl->HasLength(args,numArgs)){
|
|
return listutils::typeError("invalid number of arguments");
|
|
}
|
|
ListExpr q;
|
|
if(!getMemSubType(nl->First(args),q)){
|
|
return listutils::typeError("first arg is not a memory object");
|
|
}
|
|
if(!MemoryPQueueObject::checkType(q)){
|
|
return listutils::typeError("first arg is not a memory priority queue");
|
|
}
|
|
ListExpr tt = nl->Second(q);
|
|
ListExpr fun = nl->Second(args);
|
|
if(!listutils::isMap<1>(fun)){
|
|
return listutils::typeError("second arg is not an unary function");
|
|
}
|
|
if(!nl->Equal(nl->Second(fun),tt)){
|
|
return listutils::typeError("function argument and tuple type in "
|
|
"queue differ");
|
|
}
|
|
if(!CcReal::checkType(nl->Third(fun))){
|
|
return listutils::typeError("function result is not a real");
|
|
}
|
|
if(numArgs==2){
|
|
return listutils::basicSymbol<CcInt>();
|
|
}
|
|
ListExpr an = nl->Third(args);
|
|
if(nl->AtomType(an) != SymbolType){
|
|
return listutils::typeError("third arg is not a valid attribute name ");
|
|
}
|
|
string ann = nl->SymbolValue(an);
|
|
ListExpr attrType;
|
|
int index = listutils::findAttribute(nl->Second(tt),ann,attrType);
|
|
if(!index){
|
|
return listutils::typeError("attribute " + ann
|
|
+ " not part of the tuple");
|
|
}
|
|
if(!CcReal::checkType(attrType)){
|
|
return listutils::typeError("attribute " + ann
|
|
+ " not of type real");
|
|
}
|
|
return nl->ThreeElemList(
|
|
nl->SymbolAtom(Symbols::APPEND()),
|
|
nl->OneElemList(nl->IntAtom(index-1)),
|
|
listutils::basicSymbol<CcInt>()
|
|
);
|
|
}
|
|
|
|
class mpqreorderInfo{
|
|
|
|
public:
|
|
mpqreorderInfo(MemoryPQueueObject* _q, Word& _fun, int _attrPos):
|
|
q(_q), fun(_fun.addr), attrPos(_attrPos)
|
|
{
|
|
arg = qp->Argument(fun);
|
|
}
|
|
|
|
int compute(){
|
|
|
|
// cout << "Reorder queue entries" << endl;
|
|
// StopWatch w;
|
|
|
|
MemoryPQueueObject::queue_t nq;
|
|
int fails = 0;
|
|
while(!q->empty()){
|
|
pqueueentry e = q->pop();
|
|
if(!insertnewentry(e,nq)){
|
|
fails++;
|
|
}
|
|
}
|
|
q->swapQueue(nq);
|
|
|
|
//cout << "reordering has taken " << w.diffTimes() << endl;
|
|
|
|
return fails;
|
|
}
|
|
|
|
|
|
private:
|
|
MemoryPQueueObject* q;
|
|
Supplier fun;
|
|
int attrPos;
|
|
ArgVectorPointer arg;
|
|
Word funres;
|
|
|
|
bool insertnewentry(pqueueentry& e, MemoryPQueueObject::queue_t& q){
|
|
Tuple* t = e();
|
|
((*arg)[0]).addr = t;
|
|
qp->Request(fun,funres);
|
|
CcReal* prio = (CcReal*) funres.addr;
|
|
if(!prio->IsDefined()){
|
|
t->DeleteIfAllowed();
|
|
return false;
|
|
}
|
|
double d = prio->GetValue();
|
|
if(attrPos>=0){
|
|
t->PutAttribute(attrPos,new CcReal(true,d));
|
|
}
|
|
q.push(pqueueentry(t,d));
|
|
t->DeleteIfAllowed();
|
|
return true;
|
|
}
|
|
};
|
|
|
|
|
|
template<class Q>
|
|
int mpqreorderVMT(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
|
|
MemoryPQueueObject* q = getMemObject<MemoryPQueueObject>((Q*) args[0].addr);
|
|
result = qp->ResultStorage(s);
|
|
CcInt* res = (CcInt*) result.addr;
|
|
if(!q){
|
|
res->SetDefined(false);
|
|
return 0;
|
|
}
|
|
int attrPos = -1;
|
|
if(qp->GetNoSons(s)==4){
|
|
attrPos = ((CcInt*) args[3].addr)->GetValue();
|
|
}
|
|
mpqreorderInfo li(q, args[1], attrPos);
|
|
res->Set(true,li.compute());
|
|
|
|
return 0;
|
|
}
|
|
|
|
ValueMapping mpqreorderVM[] = {
|
|
mpqreorderVMT<Mem>,
|
|
mpqreorderVMT<MPointer>
|
|
};
|
|
|
|
int mpqreorderSelect(ListExpr args){
|
|
return Mem::checkType(nl->First(args))?0:1;
|
|
}
|
|
|
|
OperatorSpec mpqreorderSpec(
|
|
"mpqueue x fun -> int",
|
|
" _ mpqreorder [_] ",
|
|
"Changes the priorities of the contents of a memory "
|
|
"priority queue. Returns the number of failed reinsertions, "
|
|
"i.e., entries having an undefined function result.",
|
|
" query mpq mpwreorder[ 1/.Prio] count."
|
|
);
|
|
|
|
Operator mpqreorderOp(
|
|
"mpqreorder",
|
|
mpqreorderSpec.getStr(),
|
|
2,
|
|
mpqreorderVM,
|
|
mpqreorderSelect,
|
|
mpqreorderTM<2>
|
|
);
|
|
|
|
|
|
OperatorSpec mpqreorderupdateSpec(
|
|
"mpqueue x fun -> int",
|
|
" _ mpqreorderupdate [_,_] ",
|
|
"Changes the priorities of the contents of a memory "
|
|
"priority queue. Returns the number of failed reinsertions, "
|
|
"i.e., entries having an undefined function result. The "
|
|
"attribute that's name is given as the last argument is "
|
|
"changed to the new priority value.",
|
|
" query mpq mpwreorder[ 1/.Prio] count."
|
|
);
|
|
|
|
Operator mpqreorderupdateOp(
|
|
"mpqreorderupdate",
|
|
mpqreorderupdateSpec.getStr(),
|
|
2,
|
|
mpqreorderVM,
|
|
mpqreorderSelect,
|
|
mpqreorderTM<3>
|
|
);
|
|
|
|
|
|
|
|
|
|
/*
|
|
9 Operators on Memory Stacks
|
|
|
|
9.1 mcreatestack
|
|
|
|
9.1.1 Type Mapping
|
|
|
|
Stream<Tuple> -> mpointer(mem(mstack(Tuple)))
|
|
|
|
*/
|
|
ListExpr mcreatestackTM(ListExpr args){
|
|
if(!nl->HasLength(args,1)){
|
|
return listutils::typeError("two arguments expected");
|
|
}
|
|
if(!Stream<Tuple>::checkType(nl->First(args))){
|
|
return listutils::typeError("stream(tuple) expected");
|
|
}
|
|
return MPointer::wrapType( Mem::wrapType(
|
|
MemoryStackObject::wrapType(nl->Second(nl->First(args)))));
|
|
}
|
|
|
|
|
|
template<bool flob>
|
|
int mcreatestackVM(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
|
|
result = qp->ResultStorage(s);
|
|
MPointer* mp = (MPointer*) result.addr;
|
|
string dbname = getDBname();
|
|
ListExpr mtype = nl->Second(qp->GetType(s));
|
|
MemoryStackObject* stack = new MemoryStackObject(flob,
|
|
dbname,nl->ToString(mtype));
|
|
Stream<Tuple> stream(args[0]);
|
|
stream.open();
|
|
Tuple* tuple;
|
|
while((tuple=stream.request())){
|
|
stack->push(tuple);
|
|
tuple->DeleteIfAllowed();
|
|
}
|
|
stream.close();
|
|
mp->setPointer(stack);
|
|
stack->deleteIfAllowed();
|
|
return 0;
|
|
}
|
|
|
|
OperatorSpec mcreatestackSpec(
|
|
"stream<Tuple> -> mpointer(mem(mstack(Tuple)))",
|
|
" _ mcreatestack",
|
|
"Inserts incoming tuples into a newly created "
|
|
"memory stack.",
|
|
"query plz feed mcreatestack"
|
|
);
|
|
|
|
Operator mcreatestackOp(
|
|
"mcreatestack",
|
|
mcreatestackSpec.getStr(),
|
|
mcreatestackVM<false>,
|
|
Operator::SimpleSelect,
|
|
mcreatestackTM
|
|
);
|
|
|
|
|
|
Operator mcreatestackflobOp(
|
|
"mcreatestackflob",
|
|
mcreatestackSpec.getStr(),
|
|
mcreatestackVM<true>,
|
|
Operator::SimpleSelect,
|
|
mcreatestackTM
|
|
);
|
|
|
|
|
|
|
|
/*
|
|
9.2 Operator mfeedstack
|
|
|
|
*/
|
|
ListExpr mfeedstackTM(ListExpr args){
|
|
if(!nl->HasLength(args,1)){
|
|
return listutils::typeError("one argument expected");
|
|
}
|
|
ListExpr a1;
|
|
if(!getMemSubType(nl->First(args),a1)){
|
|
return listutils::typeError("first argument is not a memory object");
|
|
}
|
|
if(!MemoryStackObject::checkType(a1)){
|
|
return listutils::typeError("expected mstack");
|
|
}
|
|
return nl->TwoElemList(
|
|
listutils::basicSymbol<Stream<Tuple> >(),
|
|
nl->Second(a1));
|
|
|
|
}
|
|
|
|
class mfeedstackInfo{
|
|
public:
|
|
mfeedstackInfo(MemoryStackObject* _obj): obj(_obj){}
|
|
|
|
~mfeedstackInfo(){}
|
|
|
|
Tuple* next(){
|
|
if(obj->empty()){
|
|
return 0;
|
|
}
|
|
Tuple* t = obj->pop();
|
|
return t;
|
|
}
|
|
|
|
private:
|
|
MemoryStackObject* obj;
|
|
};
|
|
|
|
|
|
template<class T>
|
|
int mfeedstackVMT(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
|
|
mfeedstackInfo* li = (mfeedstackInfo*) local.addr;
|
|
switch(message){
|
|
case OPEN:{
|
|
if(li){
|
|
delete li;
|
|
local.addr = 0;
|
|
}
|
|
MemoryStackObject* q = getMemoryStack((T*) args[0].addr);
|
|
if(q){
|
|
local.addr = new mfeedstackInfo(q);
|
|
}
|
|
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;
|
|
}
|
|
|
|
ValueMapping mfeedstackVM[] = {
|
|
mfeedstackVMT<Mem>,
|
|
mfeedstackVMT<MPointer>
|
|
};
|
|
|
|
int mfeedstackSelect(ListExpr args){
|
|
ListExpr a = nl->First(args);
|
|
if(Mem::checkType(a)) return 0;
|
|
if(MPointer::checkType(a)) return 1;
|
|
return -1;
|
|
}
|
|
|
|
|
|
OperatorSpec mfeedstackSpec(
|
|
"MSTACK -> stream(tuple)",
|
|
" _ mfeedstack ",
|
|
"Feeds the content of a memory stack into a tuple stream. "
|
|
"In contrast to a 'normal' feed, the stack is eat up.",
|
|
"query plzstack mfeedstack count"
|
|
);
|
|
|
|
|
|
Operator mfeedstackOp(
|
|
"mfeedstack",
|
|
mfeedstackSpec.getStr(),
|
|
2,
|
|
mfeedstackVM,
|
|
mfeedstackSelect,
|
|
mfeedstackTM
|
|
);
|
|
|
|
|
|
/*
|
|
9.3 Operator ~stacksize~
|
|
|
|
We have to use a special name because in the selection
|
|
function there is no chance to get the type. Fortunately,
|
|
a lot of functions are implemented as templates.
|
|
|
|
*/
|
|
|
|
|
|
OperatorSpec stacksizeSpec(
|
|
"MSTACK -> int",
|
|
"stacksize(_)",
|
|
"Retrieves the size of a memeory stack",
|
|
"query stacksize(plzstack)"
|
|
);
|
|
|
|
ValueMapping stacksizeVM[] = {
|
|
sizeVMT<Mem, MemoryStackObject>,
|
|
sizeVMT<MPointer, MemoryStackObject>,
|
|
};
|
|
|
|
int stacksizeSelect(ListExpr args){
|
|
return Mem::checkType(nl->First(args))?0:1;
|
|
}
|
|
|
|
|
|
Operator stacksizeOp(
|
|
"stacksize",
|
|
stacksizeSpec.getStr(),
|
|
2,
|
|
stacksizeVM,
|
|
stacksizeSelect,
|
|
sizeTM<MemoryStackObject>
|
|
);
|
|
|
|
|
|
/*
|
|
9.4 insertmstack
|
|
|
|
Inserts a tuple stream into an existing memory stack
|
|
|
|
*/
|
|
|
|
ListExpr insertmstackTM(ListExpr args){
|
|
if(!nl->HasLength(args,2)){
|
|
return listutils::typeError("two arguments expected");
|
|
}
|
|
ListExpr ts = nl->First(args);
|
|
if(!Stream<Tuple>::checkType(ts)){
|
|
return listutils::typeError("first argument is not a tuple stream");
|
|
}
|
|
ListExpr s;
|
|
if(!getMemSubType(nl->Second(args),s)){
|
|
return listutils::typeError("second arg is not a memory object");
|
|
}
|
|
if(!MemoryStackObject::checkType(s)){
|
|
return listutils::typeError("second arg is not a memory stack");
|
|
}
|
|
ListExpr st = nl->Second(s);
|
|
if(!nl->Equal(st, nl->Second(ts))){
|
|
return listutils::typeError("tuple type in stack and stream differ");
|
|
}
|
|
return ts;
|
|
}
|
|
|
|
class insertmstackInfo{
|
|
|
|
public:
|
|
insertmstackInfo(Word& _stream, MemoryStackObject* _s):
|
|
stream(_stream), s(_s){
|
|
stream.open();
|
|
}
|
|
|
|
~insertmstackInfo(){
|
|
stream.close();
|
|
}
|
|
|
|
Tuple* next(){
|
|
Tuple* t = stream.request();
|
|
if(t){
|
|
s->push(t);
|
|
}
|
|
return t;
|
|
}
|
|
|
|
private:
|
|
Stream<Tuple> stream;
|
|
MemoryStackObject* s;
|
|
};
|
|
|
|
|
|
|
|
template<class T>
|
|
int insertmstackVMT(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
|
|
insertmstackInfo* li = (insertmstackInfo*) local.addr;
|
|
switch(message){
|
|
case OPEN: {
|
|
if(li){
|
|
delete li;
|
|
local.addr = 0;
|
|
}
|
|
MemoryStackObject* o = getMemObject<MemoryStackObject>((T*)
|
|
args[1].addr);
|
|
if(o){
|
|
local.addr = new insertmstackInfo(args[0],o);
|
|
}
|
|
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;
|
|
}
|
|
|
|
ValueMapping insertmstackVM[] = {
|
|
insertmstackVMT<Mem>,
|
|
insertmstackVMT<MPointer>
|
|
};
|
|
|
|
int insertmstackSelect(ListExpr args){
|
|
return Mem::checkType(nl->Second(args))?0:1;
|
|
}
|
|
|
|
OperatorSpec insertmstackSpec(
|
|
"stream(tuple) x MSTACK -> stream(tuple)",
|
|
"_ insertmstack[_]",
|
|
"Inserts incoming tuples into a memory stack.",
|
|
"query plz feed insertmstack[plzstack1] count"
|
|
);
|
|
|
|
Operator insertmstackOp(
|
|
"insertmstack",
|
|
insertmstackSpec.getStr(),
|
|
2,
|
|
insertmstackVM,
|
|
insertmstackSelect,
|
|
insertmstackTM
|
|
);
|
|
|
|
|
|
|
|
/*
|
|
Operator ~mblock~
|
|
|
|
*/
|
|
|
|
ListExpr mblockTM(ListExpr args){
|
|
if(!nl->HasLength(args,1)){
|
|
return listutils::typeError("one argument expected");
|
|
}
|
|
ListExpr a = nl->First(args);
|
|
if(!Stream<Tuple>::checkType(a)
|
|
&&!Stream<Attribute>::checkType(a)){
|
|
return listutils::typeError("strean(tuple) or stream(DATA) expected");
|
|
}
|
|
return a;
|
|
}
|
|
|
|
template<class E>
|
|
class mblockInfo{
|
|
public:
|
|
mblockInfo(Word& _stream): stream(_stream){
|
|
collect();
|
|
}
|
|
|
|
~mblockInfo(){
|
|
for(size_t i=pos;i<v.size();i++){
|
|
v[i]->DeleteIfAllowed();
|
|
}
|
|
}
|
|
|
|
E* next(){
|
|
if(pos>=v.size()){
|
|
return 0;
|
|
}
|
|
E* res = v[pos];
|
|
v[pos] = 0;
|
|
pos++;
|
|
return res;
|
|
}
|
|
|
|
private:
|
|
Stream<E> stream;
|
|
vector<E*> v;
|
|
size_t pos;
|
|
|
|
void collect(){
|
|
stream.open();
|
|
E* elem;
|
|
while((elem=stream.request())){
|
|
v.push_back(elem);
|
|
}
|
|
stream.close();
|
|
pos = 0;
|
|
}
|
|
};
|
|
|
|
|
|
|
|
template<class T>
|
|
int mblockVMT(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
mblockInfo<T>* li = (mblockInfo<T>*) local.addr;
|
|
switch(message){
|
|
case OPEN:
|
|
if(li) delete li;
|
|
local.addr = new mblockInfo<T>(args[0]);
|
|
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 -1;
|
|
}
|
|
|
|
ValueMapping mblockVM[] = {
|
|
mblockVMT<Tuple>,
|
|
mblockVMT<Attribute>
|
|
};
|
|
|
|
int mblockSelect(ListExpr args){
|
|
return Stream<Attribute>::checkType(nl->First(args))?1:0;
|
|
}
|
|
|
|
OperatorSpec mblockSpec(
|
|
"stream(X) -> stream(X), X in tuple, DATA",
|
|
"_ mblock",
|
|
"Collects the complete stream within a single "
|
|
"step before feeding the output stream. ",
|
|
"query ten feed mblock head[3] count"
|
|
);
|
|
|
|
Operator mblockOp(
|
|
"mblock",
|
|
mblockSpec.getStr(),
|
|
2,
|
|
mblockVM,
|
|
mblockSelect,
|
|
mblockTM
|
|
);
|
|
|
|
|
|
/*
|
|
10 Operators on mgraph2
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
10.1 Creation of the graph
|
|
|
|
10.1.1 Type mapping
|
|
|
|
stream(tuple) x attrname x attrname x fun
|
|
|
|
edges source target costs
|
|
|
|
*/
|
|
ListExpr createmgraph2TM(ListExpr args){
|
|
if(!nl->HasLength(args,4)){
|
|
return listutils::typeError("five arguments expected");
|
|
}
|
|
// first arg: tuple stream
|
|
ListExpr ts = nl->First(args);
|
|
if(!Stream<Tuple>::checkType(ts)){
|
|
return listutils::typeError("first argument is not a tuple stream");
|
|
}
|
|
// second arg: attribute name of source
|
|
ListExpr source_a = nl->Second(args);
|
|
if(nl->AtomType(source_a)!=SymbolType){
|
|
return listutils::typeError("second arg is not a valid symbol value");
|
|
}
|
|
string source_n = nl->SymbolValue(source_a);
|
|
ListExpr source_t;
|
|
ListExpr attrList = nl->Second(nl->Second(ts));
|
|
int source_index = listutils::findAttribute(attrList,source_n,source_t);
|
|
if(!source_index){
|
|
return listutils::typeError("Attribute " + source_n
|
|
+ " not found in tuple");
|
|
}
|
|
// check for valid node type, (int or longint)
|
|
if( !CcInt::checkType(source_t)
|
|
&& !LongInt::checkType(source_t)){
|
|
return listutils::typeError("Invalid source type required int or longint");
|
|
}
|
|
// third arg : attribute name of target
|
|
ListExpr target_a = nl->Third(args);
|
|
if(nl->AtomType(target_a)!=SymbolType){
|
|
return listutils::typeError("third arg is not a valid symbol value");
|
|
}
|
|
string target_n = nl->SymbolValue(target_a);
|
|
ListExpr target_t;
|
|
int target_index = listutils::findAttribute(attrList,target_n,target_t);
|
|
if(!target_index){
|
|
return listutils::typeError("Attribute " + target_n
|
|
+ " not found in tuple");
|
|
}
|
|
if(!nl->Equal(source_t, target_t)){
|
|
return listutils::typeError("types of source and target differ");
|
|
}
|
|
// fourth arg: cost function
|
|
ListExpr costfun = nl->Fourth(args);
|
|
if(!listutils::isMap<1>(costfun)){
|
|
return listutils::typeError("fourth arg is not an unary function");
|
|
}
|
|
if(!nl->Equal(nl->Second(costfun), nl->Second(ts))){
|
|
return listutils::typeError("tuple type and function argument of "
|
|
"cost function differ");
|
|
}
|
|
if(!CcReal::checkType(nl->Third(costfun))){
|
|
return listutils::typeError("result of cost function is not a real");
|
|
}
|
|
|
|
ListExpr newAttr = nl->ThreeElemList(
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom("MG_Source"),
|
|
listutils::basicSymbol<CcInt>()),
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom("MG_Target"),
|
|
listutils::basicSymbol<CcInt>()),
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom("MG_Cost"),
|
|
listutils::basicSymbol<CcReal>())
|
|
);
|
|
|
|
attrList = listutils::concat(attrList, newAttr);
|
|
ListExpr tt = nl->TwoElemList(
|
|
listutils::basicSymbol<Tuple>(),
|
|
attrList);
|
|
if(!Tuple::checkType(tt)){
|
|
return listutils::typeError("attribute MG_source, MG_Target, "
|
|
"or MG_Cost already present in tuple");
|
|
}
|
|
ListExpr resType = MPointer::wrapType(Mem::wrapType(
|
|
MGraph2::wrapType(tt)));
|
|
return nl->ThreeElemList(
|
|
nl->SymbolAtom(Symbols::APPEND()),
|
|
nl->TwoElemList(
|
|
nl->IntAtom(source_index-1),
|
|
nl->IntAtom(target_index-1)),
|
|
resType);
|
|
}
|
|
|
|
|
|
// T : type of node (int, longint)
|
|
template<class T, bool flob>
|
|
int createmgraph2VMT(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
|
|
result = qp->ResultStorage(s);
|
|
MPointer* mp = (MPointer*) result.addr;
|
|
|
|
ListExpr mtype = nl->Second(qp->GetType(s));
|
|
string type = nl->ToString(mtype);
|
|
string dbname = getDBname();
|
|
MGraph2* graph = new MGraph2(flob, dbname,type);
|
|
int sourcePos = ((CcInt*) args[4].addr)->GetValue();
|
|
int targetPos = ((CcInt*) args[5].addr)->GetValue();
|
|
Word costFun = args[3];
|
|
ArgVectorPointer costArg = qp->Argument(costFun.addr);
|
|
size_t lostTuples = 0;
|
|
Stream<Tuple> stream(args[0]);
|
|
stream.open();
|
|
Tuple* orig;
|
|
Word value;
|
|
while( (orig= stream.request())){
|
|
T* Source = (T*) orig->GetAttribute(sourcePos);
|
|
T* Target = (T*) orig->GetAttribute(targetPos);
|
|
(*costArg)[0] = orig;
|
|
qp->Request(costFun.addr,value);
|
|
CcReal* Costs = (CcReal*) value.addr;
|
|
if(Source->IsDefined() && Target->IsDefined() && Costs->IsDefined()){
|
|
Tuple* nt = graph->insertOrigEdge<T>(orig,Source->GetValue(),
|
|
Target->GetValue(),
|
|
Costs->GetValue());
|
|
nt->DeleteIfAllowed();
|
|
} else {
|
|
lostTuples++;
|
|
}
|
|
orig->DeleteIfAllowed();
|
|
}
|
|
stream.close();
|
|
if(lostTuples>0){
|
|
cerr << " lost " << lostTuples << " during creation of an mgraph2" << endl;
|
|
}
|
|
mp->setPointer(graph);
|
|
graph->deleteIfAllowed();
|
|
return 0;
|
|
}
|
|
|
|
|
|
ValueMapping createmgraph2VM[] ={
|
|
createmgraph2VMT<CcInt,false>,
|
|
createmgraph2VMT<LongInt,false>
|
|
};
|
|
|
|
ValueMapping createmgraph2flobVM[] ={
|
|
createmgraph2VMT<CcInt,true>,
|
|
createmgraph2VMT<LongInt,true>
|
|
};
|
|
|
|
int createmgraph2Select(ListExpr args){
|
|
ListExpr nodeType;
|
|
listutils::findAttribute( nl->Second(nl->Second(nl->First(args))),
|
|
nl->SymbolValue(nl->Second(args)),
|
|
nodeType);
|
|
return CcInt::checkType(nodeType)?0:1;
|
|
}
|
|
|
|
OperatorSpec createmgraph2Spec(
|
|
"stream(tuple) x IDENT x INDENT x fun -> mpointer(mem(mgraph2(tuple@..)))",
|
|
" edges createmgraph2[SourceAttr, TargetAttr, CostFun]",
|
|
"Creates an mgraph2 from an stream of edges. Edges with undefined "
|
|
"source, target or costs are ignored. "
|
|
"All other edges are inserted into the graph and extended by "
|
|
"new source, target, and a cost attribute.",
|
|
"query otestrel feed createmgraph2[S1_id, S2_id, "
|
|
"distance(.S1_Pos, .S2_Pos)] "
|
|
);
|
|
|
|
Operator createmgraph2Op(
|
|
"createmgraph2",
|
|
createmgraph2Spec.getStr(),
|
|
2,
|
|
createmgraph2VM,
|
|
createmgraph2Select,
|
|
createmgraph2TM
|
|
);
|
|
|
|
Operator createmgraph2flobOp(
|
|
"createmgraph2flob",
|
|
createmgraph2Spec.getStr(),
|
|
2,
|
|
createmgraph2flobVM,
|
|
createmgraph2Select,
|
|
createmgraph2TM
|
|
);
|
|
|
|
|
|
/*
|
|
10.2 mg2insertorig
|
|
|
|
This operator inserts new edges into an existing graph
|
|
in the same way as in the graph creation. The only difference
|
|
is that the graph has to exist with the correct tuple type.
|
|
Note that as in the creation double edges are allowed.
|
|
|
|
*/
|
|
|
|
ListExpr mg2insertorigTM(ListExpr args){
|
|
if(!nl->HasLength(args,5)){
|
|
return listutils::typeError("five arguments expected");
|
|
}
|
|
// first arg: tuple stream
|
|
ListExpr ts = nl->First(args);
|
|
if(!Stream<Tuple>::checkType(ts)){
|
|
return listutils::typeError("first argument is not a tuple stream");
|
|
}
|
|
// second arg: attribute name of source
|
|
ListExpr source_a = nl->Second(args);
|
|
if(nl->AtomType(source_a)!=SymbolType){
|
|
return listutils::typeError("second arg is not a valid symbol value");
|
|
}
|
|
string source_n = nl->SymbolValue(source_a);
|
|
ListExpr source_t;
|
|
ListExpr attrList = nl->Second(nl->Second(ts));
|
|
int source_index = listutils::findAttribute(attrList,source_n,source_t);
|
|
if(!source_index){
|
|
return listutils::typeError("Attribute " + source_n
|
|
+ " not found in tuple");
|
|
}
|
|
// check for valid node type, (int or longint)
|
|
if( !CcInt::checkType(source_t)
|
|
&& !LongInt::checkType(source_t)){
|
|
return listutils::typeError("Invalid source type required int or longint");
|
|
}
|
|
// third arg : attribute name of target
|
|
ListExpr target_a = nl->Third(args);
|
|
if(nl->AtomType(target_a)!=SymbolType){
|
|
return listutils::typeError("third arg is not a valid symbol value");
|
|
}
|
|
string target_n = nl->SymbolValue(target_a);
|
|
ListExpr target_t;
|
|
int target_index = listutils::findAttribute(attrList,target_n,target_t);
|
|
if(!target_index){
|
|
return listutils::typeError("Attribute " + target_n
|
|
+ " not found in tuple");
|
|
}
|
|
if(!nl->Equal(source_t, target_t)){
|
|
return listutils::typeError("types ofd source and target differ");
|
|
}
|
|
|
|
// fourth arg: cost function
|
|
ListExpr costfun = nl->Fourth(args);
|
|
if(!listutils::isMap<1>(costfun)){
|
|
return listutils::typeError("fourth arg is not an unary function");
|
|
}
|
|
if(!nl->Equal(nl->Second(costfun), nl->Second(ts))){
|
|
return listutils::typeError("tuple type and function argument of "
|
|
"cost function differ");
|
|
}
|
|
if(!CcReal::checkType(nl->Third(costfun))){
|
|
return listutils::typeError("result of cost function is not a real");
|
|
}
|
|
|
|
// fifth argument: the graph
|
|
ListExpr graph;
|
|
if(!getMemSubType(nl->Fifth(args),graph)){
|
|
return listutils::typeError("5th argument is not a memory object");
|
|
}
|
|
if(!MGraph2::checkType(graph)){
|
|
return listutils::typeError("5th arg is not an mgraph2");
|
|
}
|
|
ListExpr sAttrList = nl->Second(nl->Second(ts));
|
|
ListExpr gAttrList = nl->Second(nl->Second(graph));
|
|
if(nl->ListLength(sAttrList)+3 != nl->ListLength(gAttrList)){
|
|
return listutils::typeError("invalid number of attributes in tuple");
|
|
}
|
|
while(!nl->IsEmpty(sAttrList)){
|
|
ListExpr sf = nl->First(sAttrList);
|
|
ListExpr gf = nl->First(gAttrList);
|
|
sAttrList = nl->Rest(sAttrList);
|
|
gAttrList = nl->Rest(gAttrList);
|
|
if(!nl->Equal(sf,gf)){
|
|
return listutils::typeError("invalid tuple type (differs to graph)");
|
|
}
|
|
}
|
|
|
|
ListExpr gTuple = nl->Second(graph);
|
|
|
|
return nl->ThreeElemList(
|
|
nl->SymbolAtom(Symbols::APPEND()),
|
|
nl->TwoElemList(
|
|
nl->IntAtom(source_index-1),
|
|
nl->IntAtom(target_index-1)),
|
|
nl->TwoElemList(
|
|
listutils::basicSymbol<Stream<Tuple> >(),
|
|
gTuple)
|
|
);
|
|
}
|
|
|
|
template<class T>
|
|
class insertmgraph2Info{
|
|
|
|
public:
|
|
insertmgraph2Info( Word& _stream, MGraph2* _graph,int _sourcePos,
|
|
int _targetPos, Word& _costFun):
|
|
stream(_stream), graph(_graph), sourcePos(_sourcePos),
|
|
targetPos(_targetPos), costFun(_costFun.addr){
|
|
stream.open();
|
|
costArg = qp->Argument(costFun);
|
|
lost = 0;
|
|
}
|
|
~insertmgraph2Info(){
|
|
if(lost>0){
|
|
cout << "Lost : " << lost
|
|
<< " edges during inserting edges into a graph" << endl;
|
|
}
|
|
stream.close();
|
|
}
|
|
|
|
Tuple* next(){
|
|
Tuple* orig;
|
|
|
|
while( (orig = stream.request())) {
|
|
T* Source = (T*) orig->GetAttribute(sourcePos);
|
|
T* Target = (T*) orig->GetAttribute(targetPos);
|
|
(*costArg)[0] = orig;
|
|
qp->Request(costFun,value);
|
|
CcReal* Costs = (CcReal*) value.addr;
|
|
if(Source->IsDefined() && Target->IsDefined() && Costs->IsDefined()){
|
|
Tuple* res = graph->insertOrigEdge<T>(orig,Source->GetValue(),
|
|
Target->GetValue(),
|
|
Costs->GetValue());
|
|
orig->DeleteIfAllowed();
|
|
return res;
|
|
}
|
|
// ignore nonsense tuples
|
|
lost++;
|
|
orig->DeleteIfAllowed();
|
|
}
|
|
return 0;
|
|
}
|
|
private:
|
|
Stream<Tuple> stream;
|
|
MGraph2* graph;
|
|
int sourcePos;
|
|
int targetPos;
|
|
Supplier costFun;
|
|
ArgVectorPointer costArg;
|
|
Word value;
|
|
size_t lost;
|
|
};
|
|
|
|
|
|
|
|
template<class T, class G>
|
|
int mg2insertorigVMT(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
|
|
insertmgraph2Info<T>* li = (insertmgraph2Info<T>*)local.addr;
|
|
|
|
switch(message){
|
|
|
|
case OPEN:{
|
|
if(li){
|
|
delete li;
|
|
local.addr = 0;
|
|
}
|
|
MGraph2* graph = getMemObject<MGraph2>((G*) args[4].addr);
|
|
if(!graph){
|
|
return 0;
|
|
}
|
|
local.addr = new insertmgraph2Info<T>(
|
|
args[0], graph,
|
|
((CcInt*) args[5].addr)->GetValue(),
|
|
((CcInt*) args[6].addr)->GetValue(),
|
|
args[3]);
|
|
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;
|
|
}
|
|
|
|
ValueMapping mg2insertorigVM[] = {
|
|
mg2insertorigVMT<CcInt,Mem>,
|
|
mg2insertorigVMT<CcInt,MPointer>,
|
|
mg2insertorigVMT<LongInt,Mem>,
|
|
mg2insertorigVMT<LongInt,MPointer>
|
|
};
|
|
|
|
int mg2insertorigSelect(ListExpr args){
|
|
ListExpr nodeType;
|
|
listutils::findAttribute( nl->Second(nl->Second(nl->First(args))),
|
|
nl->SymbolValue(nl->Second(args)),
|
|
nodeType);
|
|
int n1 = CcInt::checkType(nodeType)?0:2;
|
|
int n2 = Mem::checkType(nl->Fifth(args))?0:1;
|
|
return n1 + n2;
|
|
}
|
|
|
|
OperatorSpec mg2insertorigSpec(
|
|
"stream(tuple) x IDENT x INDENT x fun x MGRAPH2 -> stream(tuple)",
|
|
" edges mg2insertorig[SourceName, TargetName, CostFun, Graph] ",
|
|
"Inserts new edges into an existing graph using the original "
|
|
"tuple representation that was used during the graph creation.",
|
|
" query edges feed mg2insertgraph[Source, Target, .Cost, mg2] count"
|
|
);
|
|
|
|
Operator mg2insertorigOp(
|
|
"mg2insertorig",
|
|
mg2insertorigSpec.getStr(),
|
|
4,
|
|
mg2insertorigVM,
|
|
mg2insertorigSelect,
|
|
mg2insertorigTM
|
|
);
|
|
|
|
/*
|
|
10.3 Operator mg2insert
|
|
|
|
*/
|
|
template<class G>
|
|
ListExpr mginsertTM(ListExpr args){
|
|
if(!nl->HasLength(args,2)){
|
|
return listutils::typeError("two arguments expected");
|
|
}
|
|
ListExpr ts = nl->First(args);
|
|
if(!Stream<Tuple>::checkType(ts)){
|
|
return listutils::typeError("first arg is not a tuple stream");
|
|
}
|
|
ListExpr graph;
|
|
if(!getMemSubType(nl->Second(args),graph)){
|
|
return listutils::typeError("second argument is not a memory object");
|
|
}
|
|
if(!G::checkType(graph)){
|
|
return listutils::typeError("second argument is not an " +
|
|
G::BasicType());
|
|
}
|
|
if(!nl->Equal(nl->Second(ts), nl->Second(graph))){
|
|
return listutils::typeError("tuple types of stream and graph differ");
|
|
}
|
|
return ts;
|
|
}
|
|
|
|
template<class G>
|
|
class mginsertInfo{
|
|
public:
|
|
mginsertInfo(Word& _stream, G* _graph): stream(_stream), graph(_graph){
|
|
stream.open();
|
|
}
|
|
|
|
~mginsertInfo(){
|
|
stream.close();
|
|
}
|
|
|
|
Tuple* next(){
|
|
Tuple* t;
|
|
while( (t = stream.request())){
|
|
if(!graph->insertGraphEdge(t)){
|
|
t->DeleteIfAllowed();
|
|
} else {
|
|
return t;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
private:
|
|
Stream<Tuple> stream;
|
|
G* graph;
|
|
};
|
|
|
|
template<class GN, class Graph>
|
|
int mginsertVMT(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
mginsertInfo<Graph>* li = (mginsertInfo<Graph>*) local.addr;
|
|
switch(message){
|
|
case OPEN: {
|
|
if(li) {
|
|
delete li;
|
|
local.addr =0;
|
|
}
|
|
Graph* g = getMemObject<Graph>((GN*)args[1].addr);
|
|
if(!g) return 0;
|
|
local.addr = new mginsertInfo<Graph>(args[0],g);
|
|
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;
|
|
}
|
|
|
|
ValueMapping mg2insertVM[] = {
|
|
mginsertVMT<Mem, MGraph2>,
|
|
mginsertVMT<MPointer, MGraph2>
|
|
};
|
|
|
|
int mginsertSelect(ListExpr args){
|
|
return Mem::checkType(nl->Second(args))?0:1;
|
|
}
|
|
|
|
OperatorSpec mg2insertSpec(
|
|
"stream<tuple> x MGRAPH2 -> stream(tuple)",
|
|
"_ mg2insert[_]",
|
|
"Inserts graph tuples into a graph."
|
|
"Tuples with invalid values are ignored and are "
|
|
"not passed to the output stream. "
|
|
"Invalid tuples may have source or target node "
|
|
"outside the graph or negative costs.",
|
|
"query newEdges feed mginsert[mg2] count"
|
|
);
|
|
|
|
|
|
Operator mg2insertOp(
|
|
"mg2insert",
|
|
mg2insertSpec.getStr(),
|
|
2,
|
|
mg2insertVM,
|
|
mginsertSelect,
|
|
mginsertTM<MGraph2>
|
|
);
|
|
|
|
/*
|
|
10.5 mgfeed
|
|
|
|
*/
|
|
template<class G>
|
|
ListExpr mgfeedTM(ListExpr args){
|
|
if(!nl->HasLength(args,1)){
|
|
return listutils::typeError("one argument expected");
|
|
}
|
|
ListExpr g = nl->First(args);
|
|
string err;
|
|
if(MPointer::checkType(g)){
|
|
g = nl->Second(g);
|
|
}
|
|
if(!Mem::checkType(g)){
|
|
return listutils::typeError("first arg must be of type mpointer or mem");
|
|
}
|
|
g = nl->Second(g);
|
|
if(!G::checkType(g)){
|
|
return listutils::typeError("argument is not a memory graph");
|
|
}
|
|
return nl->TwoElemList(
|
|
listutils::basicSymbol<Stream<Tuple> >(),
|
|
nl->Second(g));
|
|
|
|
}
|
|
|
|
|
|
template<class GN, class Graph>
|
|
int mg2feedVMT(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
|
|
typedef typename Graph::edgeIterator iterator;
|
|
iterator* li = (iterator*) local.addr;
|
|
switch(message){
|
|
case OPEN: {
|
|
if(li){
|
|
delete li;
|
|
local.addr = 0;
|
|
}
|
|
Graph* g = getMemObject<Graph>((GN*) args[0].addr);
|
|
if(!g) return 0;
|
|
local.addr = g->getEdgeIt();
|
|
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;
|
|
}
|
|
|
|
ValueMapping mg2feedVM[] = {
|
|
mg2feedVMT<Mem, MGraph2>,
|
|
mg2feedVMT<MPointer, MGraph2>
|
|
};
|
|
|
|
int mgfeedSelect(ListExpr args){
|
|
return Mem::checkType(nl->First(args))?0:1;
|
|
}
|
|
|
|
OperatorSpec mg2feedSpec(
|
|
"MGRAPH -> stream(tuple)",
|
|
" _ mg2feed",
|
|
"Extract the edges from a mgraph2 object",
|
|
"query mg2 mgfeed count"
|
|
);
|
|
|
|
|
|
Operator mg2feedOp(
|
|
"mg2feed",
|
|
mg2feedSpec.getStr(),
|
|
2,
|
|
mg2feedVM,
|
|
mgfeedSelect,
|
|
mgfeedTM<MGraph2>
|
|
);
|
|
|
|
|
|
/*
|
|
10.5 Operator mg2nodemap
|
|
|
|
*/
|
|
ListExpr mg2nodemapTM(ListExpr args){
|
|
if(!nl->HasLength(args,2)){
|
|
return listutils::typeError("two arguments required");
|
|
}
|
|
ListExpr g;
|
|
if(!getMemSubType(nl->First(args),g)){
|
|
return listutils::typeError("first arg is not a memory object");
|
|
}
|
|
if(!MGraph2::checkType(g)){
|
|
return listutils::typeError("argument is not a memory graph");
|
|
}
|
|
// check second argument
|
|
ListExpr node = nl->Second(args);
|
|
if(!CcInt::checkType(node) && !LongInt::checkType(node)){
|
|
return listutils::typeError("second arg has to be of type int or longint");
|
|
}
|
|
return listutils::basicSymbol<CcInt>();
|
|
}
|
|
|
|
|
|
template<class G, class N>
|
|
int mg2nodemapVMT(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
result = qp->ResultStorage(s);
|
|
CcInt* res = (CcInt*) result.addr;
|
|
MGraph2* g = getMemObject<MGraph2>((G*) args[0].addr);
|
|
if(!g){
|
|
res->SetDefined(false);
|
|
return 0;
|
|
}
|
|
N* v = (N*) args[1].addr;
|
|
if(!v->IsDefined()){
|
|
res->SetDefined(false);
|
|
return 0;
|
|
}
|
|
|
|
int r = g->mapNode(v->GetValue());
|
|
if(r<0){
|
|
res->SetDefined(false);
|
|
return 0;
|
|
}
|
|
res->Set(true,r);
|
|
return 0;
|
|
}
|
|
|
|
ValueMapping mg2nodemapVM[] = {
|
|
mg2nodemapVMT<Mem,CcInt>,
|
|
mg2nodemapVMT<Mem,LongInt>,
|
|
mg2nodemapVMT<MPointer,CcInt>,
|
|
mg2nodemapVMT<MPointer,LongInt>
|
|
};
|
|
|
|
int mg2nodemapSelect(ListExpr args){
|
|
int n1 = Mem::checkType(nl->First(args))?0:2;
|
|
int n2 = CcInt::checkType(nl->Second(args))?0:1;
|
|
return n1+n2;
|
|
}
|
|
|
|
OperatorSpec mg2nodemapSpec(
|
|
"MGRAPH2 x {int, longint} -> int",
|
|
"_ mg2nodemap[_]",
|
|
"Returns the internal node number for a node having "
|
|
"a nodenumber corresponding to the argument.",
|
|
"query mg2 nodemap[40]"
|
|
);
|
|
|
|
Operator mg2nodemapOp(
|
|
"mg2nodemap",
|
|
mg2nodemapSpec.getStr(),
|
|
4,
|
|
mg2nodemapVM,
|
|
mg2nodemapSelect,
|
|
mg2nodemapTM
|
|
);
|
|
|
|
/*
|
|
10.6 Operator mg2numvertices
|
|
|
|
*/
|
|
template<class Graph>
|
|
ListExpr mgnumverticesTM(ListExpr args){
|
|
if(!nl->HasLength(args,1)){
|
|
return listutils::typeError("one argument expected");
|
|
}
|
|
ListExpr g;
|
|
if(!getMemSubType(nl->First(args),g)){
|
|
return listutils::typeError("argument is not a memory object");
|
|
}
|
|
if(!Graph::checkType(g)){
|
|
return listutils::typeError("argument is not a" + Graph::BasicType());
|
|
}
|
|
return listutils::basicSymbol<CcInt>();
|
|
}
|
|
|
|
template<class GN, class Graph>
|
|
int mgnumverticesVMT(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
result = qp->ResultStorage(s);
|
|
CcInt* res = (CcInt*) result.addr;
|
|
Graph* g = getMemObject<Graph>((GN*) args[0].addr);
|
|
if(!g){
|
|
res->SetDefined(false);
|
|
return 0;
|
|
}
|
|
res->Set(true,g->numVertices());
|
|
return 0;
|
|
}
|
|
|
|
ValueMapping mg2numverticesVM[] = {
|
|
mgnumverticesVMT<Mem, MGraph2>,
|
|
mgnumverticesVMT<MPointer, MGraph2>
|
|
};
|
|
|
|
int mgnumverticesSelect(ListExpr args){
|
|
return Mem::checkType(nl->First(args))?0:1;
|
|
}
|
|
|
|
OperatorSpec mg2numverticesSpec(
|
|
"MGRAPH2 -> int",
|
|
"mg2numvertices(_)",
|
|
"Returns the number of nodes of a mgraph2 object",
|
|
"query mgenumvertices(mg2)"
|
|
);
|
|
|
|
Operator mg2numverticesOp(
|
|
"mg2numvertices",
|
|
mg2numverticesSpec.getStr(),
|
|
2,
|
|
mg2numverticesVM,
|
|
mgnumverticesSelect,
|
|
mgnumverticesTM<MGraph2>
|
|
);
|
|
|
|
/*
|
|
10.7 mgsuccessors mgpredecessors
|
|
|
|
*/
|
|
template<class Graph>
|
|
ListExpr mgsuccpredTM(ListExpr args){
|
|
if(!nl->HasLength(args,2) &&!nl->HasLength(args,3)){
|
|
return listutils::typeError("two or three arguments required");
|
|
}
|
|
ListExpr g;
|
|
if(!getMemSubType(nl->First(args),g)){
|
|
return listutils::typeError("first arg is not a memory object");
|
|
}
|
|
if(!Graph::checkType(g)){
|
|
return listutils::typeError("argument is not a " + Graph::BasicType());
|
|
}
|
|
// check second argument
|
|
ListExpr node = nl->Second(args);
|
|
if(!CcInt::checkType(node) ){
|
|
return listutils::typeError("second arg has to be of type int");
|
|
}
|
|
ListExpr resType = Stream<Tuple>::wrap(nl->Second(g));
|
|
if(nl->HasLength(args,3)){
|
|
if(!CcBool::checkType(nl->Third(args))){
|
|
return listutils::typeError("third argument is not of type bool");
|
|
}
|
|
return resType;
|
|
}
|
|
// optional bool argument missing, add default
|
|
return nl->ThreeElemList(nl->SymbolAtom(Symbols::APPEND()),
|
|
nl->OneElemList(nl->BoolAtom(false)),
|
|
resType);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class GN, class Graph, bool isSucc>
|
|
int mgsuccpredVMT(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
|
|
typedef typename Graph::singleNodeIterator iterator;
|
|
iterator* li = (iterator*) local.addr;
|
|
|
|
switch(message){
|
|
case OPEN: {
|
|
if(li){
|
|
delete li;
|
|
local.addr = 0;
|
|
}
|
|
// graph
|
|
Graph* g = getMemObject<Graph>((GN*) args[0].addr);
|
|
if(!g){
|
|
return 0;
|
|
}
|
|
// node
|
|
CcInt* v = (CcInt*) args[1].addr;
|
|
if(!v->IsDefined()){
|
|
return 0;
|
|
}
|
|
// delete option
|
|
CcBool* DelOption = (CcBool*) args[2].addr;
|
|
if(!DelOption->IsDefined()){
|
|
return 0;
|
|
}
|
|
bool delOption = DelOption->GetValue();
|
|
if(isSucc){
|
|
local.addr = g->getSuccessors(v->GetValue(),delOption);
|
|
} else {
|
|
local.addr = g->getPredecessors(v->GetValue(),delOption);
|
|
}
|
|
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;
|
|
}
|
|
|
|
ValueMapping mg2successorsVM[] = {
|
|
mgsuccpredVMT<Mem,MGraph2,true>,
|
|
mgsuccpredVMT<MPointer,MGraph2,true>
|
|
};
|
|
|
|
ValueMapping mg2predecessorsVM[] = {
|
|
mgsuccpredVMT<Mem,MGraph2,false>,
|
|
mgsuccpredVMT<MPointer,MGraph2,false>
|
|
};
|
|
|
|
int mgsuccpredSelect(ListExpr args){
|
|
return Mem::checkType(nl->First(args))?0:1;
|
|
}
|
|
|
|
OperatorSpec mg2successorsSpec(
|
|
"MGRAPH2 x int [x bool] -> stream(tuple)",
|
|
"_ mg2successors [_]",
|
|
"returns the successors of a specified node."
|
|
"if the optional boolean argument exist with value true,"
|
|
" all outgoing edges of this node are removed. This holds "
|
|
"also in the case that only a part of these edges are "
|
|
"put into result stream (e.g., restricted by a head).",
|
|
"query mg2 mg2successors[0] count"
|
|
);
|
|
|
|
OperatorSpec mg2predecessorsSpec(
|
|
"MGRAPH2 x int [x bool] -> stream(tuple)",
|
|
"_ mg2predecessors [_]",
|
|
"returns the predecessors of a specified node.",
|
|
"if the optional boolean argument exist with value true,"
|
|
" all incoming edges of this node are removed. This holds "
|
|
"also in the case that only a part of these edges are "
|
|
"put into result stream (e.g., restricted by a head).",
|
|
"query mg2 mg2predecessors[0] count"
|
|
);
|
|
|
|
Operator mg2successorsOp(
|
|
"mg2successors",
|
|
mg2successorsSpec.getStr(),
|
|
2,
|
|
mg2successorsVM,
|
|
mgsuccpredSelect,
|
|
mgsuccpredTM<MGraph2>
|
|
);
|
|
|
|
|
|
Operator mg2predecessorsOp(
|
|
"mg2predecessors",
|
|
mg2predecessorsSpec.getStr(),
|
|
2,
|
|
mg2predecessorsVM,
|
|
mgsuccpredSelect,
|
|
mgsuccpredTM<MGraph2>
|
|
);
|
|
|
|
/*
|
|
10.7 number of predecessors and successors
|
|
|
|
*/
|
|
template<class Graph>
|
|
ListExpr mgnumsuccpredTM(ListExpr args){
|
|
if(!nl->HasLength(args,2)){
|
|
return listutils::typeError("two arguments required");
|
|
}
|
|
ListExpr g;
|
|
if(!getMemSubType(nl->First(args),g)){
|
|
return listutils::typeError("first arg is not a memory object");
|
|
}
|
|
if(!Graph::checkType(g)){
|
|
return listutils::typeError("argument is not a " + Graph::BasicType());
|
|
}
|
|
// check second argument
|
|
ListExpr node = nl->Second(args);
|
|
if(!CcInt::checkType(node) ){
|
|
return listutils::typeError("second arg has to be of type int");
|
|
}
|
|
return listutils::basicSymbol<CcInt>();
|
|
}
|
|
|
|
template<class GN, class Graph, bool isSucc>
|
|
int mgnumsuccpredVMT(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
result = qp->ResultStorage(s);
|
|
CcInt* res = (CcInt*) result.addr;
|
|
Graph* g = getMemObject<Graph>((GN*) args[0].addr);
|
|
if(!g){
|
|
res->SetDefined(false);
|
|
return 0;
|
|
}
|
|
CcInt* v = (CcInt*) args[1].addr;
|
|
if(!v->IsDefined()){
|
|
res->SetDefined(false);
|
|
return 0;
|
|
}
|
|
int c = isSucc?g->succCount(v->GetValue()):g->predCount(v->GetValue());
|
|
if(c<0){
|
|
res->SetDefined(false);
|
|
return 0;
|
|
}
|
|
res->Set(true,c);
|
|
return 0;
|
|
}
|
|
|
|
|
|
ValueMapping mg2numsuccessorsVM[] = {
|
|
mgnumsuccpredVMT<Mem,MGraph2,true>,
|
|
mgnumsuccpredVMT<MPointer,MGraph2,true>
|
|
};
|
|
|
|
ValueMapping mg2numpredecessorsVM[] = {
|
|
mgnumsuccpredVMT<Mem,MGraph2,false>,
|
|
mgnumsuccpredVMT<MPointer,MGraph2,false>
|
|
};
|
|
|
|
int mgnumsuccpredSelect(ListExpr args){
|
|
return Mem::checkType(nl->First(args))?0:1;
|
|
}
|
|
|
|
OperatorSpec mg2numsuccessorsSpec(
|
|
"MGRAPH2 x int -> int",
|
|
"_ mg2numsuccessors[_]",
|
|
"Return the count of successors of a vertex.",
|
|
"query mg2 mg2numsuccessors[1] "
|
|
);
|
|
|
|
OperatorSpec mg2numpredecessorsSpec(
|
|
"MGRAPH2 x int -> int",
|
|
"_ mg2numpredecessors[_]",
|
|
"Return the count of predecessors of a vertex.",
|
|
"query mg2 mg2numpredecessors[1] "
|
|
);
|
|
|
|
Operator mg2numsuccessorsOp(
|
|
"mg2numsuccessors",
|
|
mg2numsuccessorsSpec.getStr(),
|
|
2,
|
|
mg2numsuccessorsVM,
|
|
mgnumsuccpredSelect,
|
|
mgnumsuccpredTM<MGraph2>
|
|
);
|
|
|
|
Operator mg2numpredecessorsOp(
|
|
"mg2numpredecessors",
|
|
mg2numpredecessorsSpec.getStr(),
|
|
2,
|
|
mg2numpredecessorsVM,
|
|
mgnumsuccpredSelect,
|
|
mgnumsuccpredTM<MGraph2>
|
|
);
|
|
|
|
/*
|
|
10.8 mg2disconnect
|
|
|
|
*/
|
|
template<class Graph>
|
|
ListExpr mgdisconnectTM(ListExpr args){
|
|
if(!nl->HasLength(args,2)){
|
|
return listutils::typeError("two arguments required");
|
|
}
|
|
ListExpr g;
|
|
if(!getMemSubType(nl->First(args),g)){
|
|
return listutils::typeError("first arg is not a memory object");
|
|
}
|
|
if(!Graph::checkType(g)){
|
|
return listutils::typeError("argument is not a " + Graph::BasicType());
|
|
}
|
|
// check second argument
|
|
ListExpr node = nl->Second(args);
|
|
if(!CcInt::checkType(node) ){
|
|
return listutils::typeError("second arg has to be of type int");
|
|
}
|
|
return listutils::basicSymbol<CcBool>();
|
|
}
|
|
|
|
template<class GN, class Graph>
|
|
int mgdisconnectVMT(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
result = qp->ResultStorage(s);
|
|
CcBool* res = (CcBool*) result.addr;
|
|
Graph* g = getMemObject<Graph>((GN*) args[0].addr);
|
|
if(!g){
|
|
res->SetDefined(false);
|
|
return 0;
|
|
}
|
|
CcInt* v = (CcInt*) args[1].addr;
|
|
if(!v->IsDefined()){
|
|
res->SetDefined(false);
|
|
return 0;
|
|
}
|
|
res->Set(true,g->disconnect(v->GetValue()));
|
|
return 0;
|
|
}
|
|
|
|
ValueMapping mg2disconnectVM[] = {
|
|
mgdisconnectVMT<Mem, MGraph2>,
|
|
mgdisconnectVMT<MPointer, MGraph2>
|
|
};
|
|
|
|
int mgdisconnectSelect(ListExpr args){
|
|
return Mem::checkType(nl->First(args))?0:1;
|
|
}
|
|
|
|
|
|
OperatorSpec mg2disconnectSpec(
|
|
"MGRAPH2 x int -> bool",
|
|
"_ mg2disconnect[_]",
|
|
"Disconnects a specified node from the remainder of the graph",
|
|
"query mg2 mg2disconnect[6] "
|
|
);
|
|
|
|
|
|
Operator mg2disconnectOp(
|
|
"mg2disconnect",
|
|
mg2disconnectSpec.getStr(),
|
|
2,
|
|
mg2disconnectVM,
|
|
mgdisconnectSelect,
|
|
mgdisconnectTM<MGraph2>
|
|
);
|
|
|
|
|
|
/*
|
|
deleteEdges
|
|
|
|
*/
|
|
template<class G>
|
|
ListExpr mgdeleteEdgesTM(ListExpr args){
|
|
if(!nl->HasLength(args,3)){
|
|
return listutils::typeError("three arguments expected");
|
|
}
|
|
ListExpr g;
|
|
if(!getMemSubType(nl->First(args),g)){
|
|
return listutils::typeError("first arg is not a memory object");
|
|
}
|
|
if(!G::checkType(g)){
|
|
return listutils::typeError("argument is not a " + G::BasicType());
|
|
}
|
|
if(!CcInt::checkType(nl->Second(args))){
|
|
return listutils::typeError("second argument is not an int");
|
|
}
|
|
if(!CcInt::checkType(nl->Third(args))){
|
|
return listutils::typeError("third argument is not an int");
|
|
}
|
|
return listutils::basicSymbol<CcBool>();
|
|
}
|
|
|
|
|
|
template<class GN, class Graph>
|
|
int mgdeleteEdgesVMT(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
result = qp->ResultStorage(s);
|
|
CcBool* res = (CcBool*) result.addr;
|
|
Graph* g = getMemObject<Graph>((GN*) args[0].addr);
|
|
if(!g){
|
|
res->SetDefined(false);
|
|
return 0;
|
|
}
|
|
CcInt* source = (CcInt*) args[1].addr;
|
|
CcInt* target = (CcInt*) args[2].addr;
|
|
if(!source->IsDefined() || !target->IsDefined()){
|
|
res->SetDefined(false);
|
|
return 0;
|
|
}
|
|
g->removeAllEdges(source->GetValue(), target->GetValue());
|
|
res->Set(true,true);
|
|
return 0;
|
|
}
|
|
|
|
|
|
ValueMapping mg2deleteEdgesVM[] = {
|
|
mgdeleteEdgesVMT<Mem, MGraph2>,
|
|
mgdeleteEdgesVMT<MPointer, MGraph2>
|
|
};
|
|
|
|
int mgdeleteEdgesSelect(ListExpr args){
|
|
return Mem::checkType(nl->First(args))?0:1;
|
|
}
|
|
|
|
|
|
OperatorSpec mg2deleteEdgesSpec(
|
|
"MGRAPH2 x int x int -> bool",
|
|
"graph mg2deleteEdges[source, target]",
|
|
"Removes all edges from source to target in graph.",
|
|
"query mg2 mg2deleteEdges[2,7] "
|
|
);
|
|
|
|
|
|
Operator mg2deleteEdgesOp(
|
|
"mg2deleteEdges",
|
|
mg2deleteEdgesSpec.getStr(),
|
|
2,
|
|
mg2deleteEdgesVM,
|
|
mgdeleteEdgesSelect,
|
|
mgdeleteEdgesTM<MGraph2>
|
|
);
|
|
|
|
|
|
/*
|
|
11 Operators for mgraph3
|
|
|
|
*/
|
|
ListExpr createmgraph3TM(ListExpr args){
|
|
// stream(tuple) x SourceName x TargetName x CostName x Size
|
|
if(!nl->HasLength(args,5)){
|
|
return listutils::typeError("5 args expected");
|
|
}
|
|
// first arg: tuple stream
|
|
ListExpr ts = nl->First(args);
|
|
if(!Stream<Tuple>::checkType(ts)){
|
|
return listutils::typeError("First arg is not a tuple stream");
|
|
}
|
|
ListExpr tupleType = nl->Second(ts);
|
|
// second arg: name of src
|
|
ListExpr sn = nl->Second(args);
|
|
if(nl->AtomType(sn)!=SymbolType){
|
|
return listutils::typeError("second arg is not a valid attribute name");
|
|
}
|
|
string src = nl->SymbolValue(sn);
|
|
ListExpr attrType;
|
|
ListExpr attrList = nl->Second(tupleType);
|
|
int srcIndex = listutils::findAttribute(attrList, src,attrType);
|
|
if(!srcIndex){
|
|
return listutils::typeError("attribute " + src + " not part of the tuple");
|
|
}
|
|
if(!CcInt::checkType(attrType)){
|
|
return listutils::typeError("attribute " + src + " not of type int");
|
|
}
|
|
// third arg: name of target
|
|
ListExpr tn = nl->Third(args);
|
|
if(nl->AtomType(tn)!=SymbolType){
|
|
return listutils::typeError("third arg is not a valid attribute name");
|
|
}
|
|
string target = nl->SymbolValue(tn);
|
|
int targetIndex = listutils::findAttribute(attrList, target,attrType);
|
|
if(!targetIndex){
|
|
return listutils::typeError("attribute " + target
|
|
+ " not part of the tuple");
|
|
}
|
|
if(!CcInt::checkType(attrType)){
|
|
return listutils::typeError("attribute " + target + " not of type int");
|
|
}
|
|
// fourth arg: name of cost
|
|
ListExpr cn = nl->Fourth(args);
|
|
if(nl->AtomType(cn)!=SymbolType){
|
|
return listutils::typeError("fourth arg is not a valid attribute name");
|
|
}
|
|
string cost = nl->SymbolValue(cn);
|
|
int costIndex = listutils::findAttribute(attrList, cost,attrType);
|
|
if(!costIndex){
|
|
return listutils::typeError("attribute " + cost
|
|
+ " not part of the tuple");
|
|
}
|
|
if(!CcReal::checkType(attrType)){
|
|
return listutils::typeError("attribute " + cost + " not of type real");
|
|
}
|
|
// fifth arg: graph size
|
|
ListExpr size = nl->Fifth(args);
|
|
if(!CcInt::checkType(size)){
|
|
return listutils::typeError("fifth attribute is not of type int");
|
|
}
|
|
|
|
ListExpr resType = MPointer::wrapType( Mem::wrapType(
|
|
MGraph3::wrapType(tupleType)));
|
|
|
|
|
|
cout << "result type = " << nl->ToString(resType) << endl;
|
|
|
|
return nl->ThreeElemList(
|
|
nl->SymbolAtom(Symbols::APPEND()),
|
|
nl->ThreeElemList( nl->IntAtom(srcIndex-1),
|
|
nl->IntAtom(targetIndex-1),
|
|
nl->IntAtom(costIndex-1)),
|
|
resType
|
|
);
|
|
}
|
|
|
|
|
|
template<bool flob>
|
|
int createmgraph3VMT(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
|
|
result = qp->ResultStorage(s);
|
|
MPointer* mp = (MPointer*) result.addr;
|
|
CcInt* Size = (CcInt*) args[4].addr;
|
|
if(!Size->IsDefined()){
|
|
mp->setPointer(0);
|
|
return 0;
|
|
}
|
|
int size = Size->GetValue();
|
|
if(size<=0){
|
|
mp->setPointer(0);
|
|
return 0;
|
|
}
|
|
int srcPos = ((CcInt*) args[5].addr)->GetValue();
|
|
int targetPos = ((CcInt*) args[6].addr)->GetValue();
|
|
int costPos = ((CcInt*) args[7].addr)->GetValue();
|
|
ListExpr memType = nl->Second(qp->GetType(s));
|
|
MGraph3* mg3 = new MGraph3(flob, getDBname(),
|
|
nl->ToString(memType),
|
|
srcPos, targetPos, costPos,
|
|
size);
|
|
|
|
Stream<Tuple> stream(args[0]);
|
|
stream.open();
|
|
Tuple* tuple;
|
|
size_t lost = 0;
|
|
while( (tuple = stream.request())){
|
|
if(!mg3->insertGraphEdge(tuple)){
|
|
lost++;
|
|
}
|
|
tuple->DeleteIfAllowed();
|
|
}
|
|
stream.close();
|
|
mp->setPointer(mg3);
|
|
mg3->deleteIfAllowed();
|
|
return 0;
|
|
}
|
|
|
|
OperatorSpec createmgraph3Spec(
|
|
"stream(tuple) x IDENT x IDENT x IDENT x int -> "
|
|
"mpointer(mem(mgraph3(tuple)))",
|
|
"edges createmgraph3[Src, Target, Cost, Size] ",
|
|
"Creates an mgraph3 object in main memory using the given size. The graph "
|
|
"will have Size vertices numbered from 0..Size-1. "
|
|
"The Edges are defined by the incoming tuples. Src and Target must be "
|
|
"attributes of the edges of type int. Cost is an attribute of the edges "
|
|
"of type real. "
|
|
"Edges having undefined or negative costs are "
|
|
"not inserted into the graph. The same holds for edges having invalid "
|
|
"Source or Target (undefined or outside the range [0,Size-1]).",
|
|
"query rel feed createmgraph3[Id_s1, Id_s2, Cost, 1024"
|
|
);
|
|
|
|
Operator createmgraph3Op(
|
|
"createmgraph3",
|
|
createmgraph3Spec.getStr(),
|
|
createmgraph3VMT<false>,
|
|
Operator::SimpleSelect,
|
|
createmgraph3TM
|
|
);
|
|
|
|
Operator createmgraph3flobOp(
|
|
"createmgraph3flob",
|
|
createmgraph3Spec.getStr(),
|
|
createmgraph3VMT<true>,
|
|
Operator::SimpleSelect,
|
|
createmgraph3TM
|
|
);
|
|
|
|
/*
|
|
11.2 inserting new edges using mg3insert
|
|
|
|
*/
|
|
|
|
ValueMapping mg3insertVM[] = {
|
|
mginsertVMT<Mem, MGraph3>,
|
|
mginsertVMT<MPointer, MGraph3>
|
|
};
|
|
|
|
|
|
OperatorSpec mg3insertSpec(
|
|
"stream<tuple> x MGRAPH3 -> stream(tuple)",
|
|
"_ mg2insert[_]",
|
|
"Inserts tuples into an existing graph."
|
|
"Tuples with invalid values are ignored and are "
|
|
"not passed to the output stream. "
|
|
"Invalid tuples may have source or target node "
|
|
"outside the graph or negative costs.",
|
|
"query newEdges feed mginsert[mg3] count"
|
|
);
|
|
|
|
|
|
Operator mg3insertOp(
|
|
"mg3insert",
|
|
mg3insertSpec.getStr(),
|
|
2,
|
|
mg3insertVM,
|
|
mginsertSelect,
|
|
mginsertTM<MGraph3>
|
|
);
|
|
|
|
|
|
/*
|
|
11.3 Operator mg3feed
|
|
|
|
*/
|
|
|
|
ValueMapping mg3feedVM[] = {
|
|
mg2feedVMT<Mem, MGraph3>,
|
|
mg2feedVMT<MPointer, MGraph3>
|
|
};
|
|
|
|
|
|
OperatorSpec mg3feedSpec(
|
|
"MGRAPH3 -> stream(tuple)",
|
|
" _ mg3feed",
|
|
"Extract the edges from a mgraph3 object",
|
|
"query mg3 mgfeed count"
|
|
);
|
|
|
|
|
|
Operator mg3feedOp(
|
|
"mg3feed",
|
|
mg3feedSpec.getStr(),
|
|
2,
|
|
mg3feedVM,
|
|
mgfeedSelect,
|
|
mgfeedTM<MGraph3>
|
|
);
|
|
|
|
|
|
/*
|
|
Number of vertices
|
|
|
|
*/
|
|
|
|
ValueMapping mg3numverticesVM[] = {
|
|
mgnumverticesVMT<Mem, MGraph3>,
|
|
mgnumverticesVMT<MPointer, MGraph3>
|
|
};
|
|
|
|
OperatorSpec mg3numverticesSpec(
|
|
"MGRAPH3 -> int",
|
|
"mg3numvertices(_)",
|
|
"Returns the number of nodes of a mgraph3 object",
|
|
"query mg3numvertices(mg3)"
|
|
);
|
|
|
|
Operator mg3numverticesOp(
|
|
"mg3numvertices",
|
|
mg3numverticesSpec.getStr(),
|
|
2,
|
|
mg3numverticesVM,
|
|
mgnumverticesSelect,
|
|
mgnumverticesTM<MGraph3>
|
|
);
|
|
|
|
|
|
/*
|
|
Successors, Predecessors
|
|
|
|
*/
|
|
|
|
ValueMapping mg3successorsVM[] = {
|
|
mgsuccpredVMT<Mem,MGraph3,true>,
|
|
mgsuccpredVMT<MPointer,MGraph3,true>
|
|
};
|
|
|
|
ValueMapping mg3predecessorsVM[] = {
|
|
mgsuccpredVMT<Mem,MGraph3,false>,
|
|
mgsuccpredVMT<MPointer,MGraph3,false>
|
|
};
|
|
|
|
|
|
OperatorSpec mg3successorsSpec(
|
|
"MGRAPH3 x int [x bool] -> stream(tuple)",
|
|
"_ mg3successors [_]",
|
|
"returns the successors of a specified node.",
|
|
"if the optional boolean argument exist with value true,"
|
|
" all outgoing edges of this node are removed. This holds "
|
|
"also in the case that only a part of these edges are "
|
|
"put into result stream (e.g., restricted by a head).",
|
|
"query mg3 mg3successors[0] count"
|
|
);
|
|
|
|
OperatorSpec mg3predecessorsSpec(
|
|
"MGRAPH3 x int [x bool] -> stream(tuple)",
|
|
"_ mg3predecessors [_]",
|
|
"returns the predecessors of a specified node.",
|
|
"if the optional boolean argument exist with value true,"
|
|
" all incoming edges of this node are removed. This holds "
|
|
"also in the case that only a part of these edges are "
|
|
"put into result stream (e.g., restricted by a head).",
|
|
"query mg3 mg3predecessors[0,FALSE] count"
|
|
);
|
|
|
|
Operator mg3successorsOp(
|
|
"mg3successors",
|
|
mg3successorsSpec.getStr(),
|
|
2,
|
|
mg3successorsVM,
|
|
mgsuccpredSelect,
|
|
mgsuccpredTM<MGraph3>
|
|
);
|
|
|
|
|
|
Operator mg3predecessorsOp(
|
|
"mg3predecessors",
|
|
mg3predecessorsSpec.getStr(),
|
|
2,
|
|
mg3predecessorsVM,
|
|
mgsuccpredSelect,
|
|
mgsuccpredTM<MGraph3>
|
|
);
|
|
|
|
|
|
/*
|
|
Number of successors / predecessors
|
|
|
|
*/
|
|
ValueMapping mg3numsuccessorsVM[] = {
|
|
mgnumsuccpredVMT<Mem,MGraph3,true>,
|
|
mgnumsuccpredVMT<MPointer,MGraph3,true>
|
|
};
|
|
|
|
ValueMapping mg3numpredecessorsVM[] = {
|
|
mgnumsuccpredVMT<Mem,MGraph3,false>,
|
|
mgnumsuccpredVMT<MPointer,MGraph3,false>
|
|
};
|
|
|
|
|
|
OperatorSpec mg3numsuccessorsSpec(
|
|
"MGRAPH3 x int -> int",
|
|
"_ mg3numsuccessors[_]",
|
|
"Return the count of successors of a vertex.",
|
|
"query mg3 mg3numsuccessors[1] "
|
|
);
|
|
|
|
OperatorSpec mg3numpredecessorsSpec(
|
|
"MGRAPH3 x int -> int",
|
|
"_ mg3numpredecessors[_]",
|
|
"Return the count of predecessors of a vertex.",
|
|
"query mg3 mg3numpredecessors[1] "
|
|
);
|
|
|
|
Operator mg3numsuccessorsOp(
|
|
"mg3numsuccessors",
|
|
mg3numsuccessorsSpec.getStr(),
|
|
2,
|
|
mg3numsuccessorsVM,
|
|
mgnumsuccpredSelect,
|
|
mgnumsuccpredTM<MGraph3>
|
|
);
|
|
|
|
Operator mg3numpredecessorsOp(
|
|
"mg3numpredecessors",
|
|
mg3numpredecessorsSpec.getStr(),
|
|
2,
|
|
mg3numpredecessorsVM,
|
|
mgnumsuccpredSelect,
|
|
mgnumsuccpredTM<MGraph3>
|
|
);
|
|
|
|
/*
|
|
disconect
|
|
|
|
*/
|
|
|
|
ValueMapping mg3disconnectVM[] = {
|
|
mgdisconnectVMT<Mem, MGraph3>,
|
|
mgdisconnectVMT<MPointer, MGraph3>
|
|
};
|
|
|
|
OperatorSpec mg3disconnectSpec(
|
|
"MGRAPH3 x int -> bool",
|
|
"_ mg3disconnect[_]",
|
|
"Disconnects a specified node from the rest of the graph",
|
|
"query mg3 mg3disconnect[6] "
|
|
);
|
|
|
|
|
|
Operator mg3disconnectOp(
|
|
"mg3disconnect",
|
|
mg3disconnectSpec.getStr(),
|
|
3,
|
|
mg3disconnectVM,
|
|
mgdisconnectSelect,
|
|
mgdisconnectTM<MGraph3>
|
|
);
|
|
|
|
|
|
/*
|
|
mg3deleteEdges
|
|
|
|
*/
|
|
|
|
ValueMapping mg3deleteEdgesVM[] = {
|
|
mgdeleteEdgesVMT<Mem, MGraph3>,
|
|
mgdeleteEdgesVMT<MPointer, MGraph3>
|
|
};
|
|
|
|
|
|
OperatorSpec mg3deleteEdgesSpec(
|
|
"MGRAPH3 x int x int -> bool",
|
|
"graph mg3deleteEdges[source, target]",
|
|
"Removes all edges from source to target in graph.",
|
|
"query mg3 mg3deleteEdges[2,7] "
|
|
);
|
|
|
|
|
|
Operator mg3deleteEdgesOp(
|
|
"mg3deleteEdges",
|
|
mg3deleteEdgesSpec.getStr(),
|
|
2,
|
|
mg3deleteEdgesVM,
|
|
mgdeleteEdgesSelect,
|
|
mgdeleteEdgesTM<MGraph3>
|
|
);
|
|
|
|
|
|
|
|
/*
|
|
Operator mgconnectedcomponents
|
|
|
|
*/
|
|
template<class G,bool perNode>
|
|
ListExpr mg23connectedcomponentsTM(ListExpr args){
|
|
if(!nl->HasLength(args,1)){
|
|
return listutils::typeError("one argument expected");
|
|
}
|
|
ListExpr graph;
|
|
if(!getMemSubType(nl->First(args), graph)){
|
|
return listutils::typeError("argument is not a memory object");
|
|
}
|
|
if(!G::checkType(graph)){
|
|
return listutils::typeError("arg is not of type " + G::BasicType());
|
|
}
|
|
ListExpr attrList = nl->Second(nl->Second(graph));
|
|
ListExpr d;
|
|
|
|
if(!perNode){
|
|
if(listutils::findAttribute(attrList,"CompNo",d)){
|
|
return listutils::typeError("Graph representation contains an "
|
|
"attribute CompNo");
|
|
}
|
|
ListExpr cl = nl->OneElemList(nl->TwoElemList(
|
|
nl->SymbolAtom("CompNo"),
|
|
listutils::basicSymbol<CcInt>()));
|
|
attrList = listutils::concat(attrList,cl);
|
|
} else {
|
|
if(listutils::findAttribute(attrList,"SourceComp",d)){
|
|
return listutils::typeError("Graph representation contains an "
|
|
"attribute SourceComp");
|
|
}
|
|
if(listutils::findAttribute(attrList,"TargetComp",d)){
|
|
return listutils::typeError("Graph representation contains an "
|
|
"attribute TargetComp");
|
|
}
|
|
ListExpr cl = nl->TwoElemList(
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom("SourceComp"),
|
|
listutils::basicSymbol<CcInt>()),
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom("TargetComp"),
|
|
listutils::basicSymbol<CcInt>())
|
|
);
|
|
attrList = listutils::concat(attrList,cl);
|
|
}
|
|
|
|
return Stream<Tuple>::wrap(Tuple::wrap(attrList));
|
|
}
|
|
|
|
template<bool perNode>
|
|
class mg23connectedcomponentsInfo{
|
|
public:
|
|
mg23connectedcomponentsInfo(MGraphCommon* _g, TupleType* _tt):
|
|
graph(_g),tt(_tt){
|
|
tt->IncReference();
|
|
graph->components(compInfo);
|
|
pos = 0;
|
|
if(pos<graph->numVertices()){
|
|
it = graph->getSuccList(pos).begin();
|
|
}
|
|
}
|
|
|
|
~mg23connectedcomponentsInfo(){
|
|
tt->DeleteIfAllowed();
|
|
}
|
|
|
|
Tuple* next(){
|
|
while(pos < graph->numVertices()){
|
|
if(it != graph->getSuccList(pos).end()){
|
|
Tuple* t = createResultTuple(*it);
|
|
it++;
|
|
return t;
|
|
}
|
|
pos++;
|
|
if(pos<graph->numVertices()){
|
|
it = graph->getSuccList(pos).begin();
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
private:
|
|
MGraphCommon* graph;
|
|
TupleType* tt;
|
|
vector<int> compInfo;
|
|
size_t pos;
|
|
list<MEdge>::const_iterator it;
|
|
|
|
Tuple* createResultTuple(const MEdge& e){
|
|
const Tuple* src = e.info;
|
|
Tuple* res = new Tuple(tt);
|
|
for(int i=0;i<src->GetNoAttributes();i++){
|
|
res->CopyAttribute(i,src,i);
|
|
}
|
|
if(!perNode){
|
|
int comp = compInfo[pos] == compInfo[e.target]?compInfo[pos]:-2;
|
|
res->PutAttribute(src->GetNoAttributes(),new CcInt(true,comp));
|
|
} else {
|
|
int sourceComp = compInfo[pos];
|
|
int targetComp = compInfo[e.target];
|
|
res->PutAttribute(src->GetNoAttributes(),new CcInt(true,sourceComp));
|
|
res->PutAttribute(src->GetNoAttributes()+1,
|
|
new CcInt(true,targetComp));
|
|
}
|
|
return res;
|
|
}
|
|
|
|
};
|
|
|
|
template<class GN, class Graph, bool perNode>
|
|
int mg23connectedcomponentsVMT(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
|
|
mg23connectedcomponentsInfo<perNode>* li =
|
|
(mg23connectedcomponentsInfo<perNode>*) local.addr;
|
|
switch(message){
|
|
case INIT: {
|
|
qp->GetLocal2(s).addr = new TupleType(
|
|
nl->Second(GetTupleResultType(s)));
|
|
return 0;
|
|
}
|
|
case FINISH: {
|
|
TupleType* tt = (TupleType*) qp->GetLocal2(s).addr;
|
|
if(tt){
|
|
tt->DeleteIfAllowed();
|
|
qp->GetLocal2(s).addr=0;
|
|
}
|
|
return 0;
|
|
}
|
|
case OPEN: {
|
|
if(li){
|
|
delete li;
|
|
local.addr = 0;
|
|
}
|
|
MGraphCommon* g = getMemObject<Graph>((GN*) args[0].addr);
|
|
if(!g){
|
|
return 0;
|
|
}
|
|
TupleType* tt = (TupleType*) qp->GetLocal2(s).addr;
|
|
local.addr = new mg23connectedcomponentsInfo<perNode>(g,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 -1;
|
|
}
|
|
|
|
int mg23connectedcomponentsSelect(ListExpr args){
|
|
return Mem::checkType(nl->First(args))?0:1;
|
|
}
|
|
|
|
ValueMapping mg2connectedcomponentsVM [] = {
|
|
mg23connectedcomponentsVMT<Mem,MGraph2, false>,
|
|
mg23connectedcomponentsVMT<MPointer,MGraph2, false>
|
|
};
|
|
|
|
ValueMapping mg3connectedcomponentsVM [] = {
|
|
mg23connectedcomponentsVMT<Mem,MGraph3, false>,
|
|
mg23connectedcomponentsVMT<MPointer,MGraph3, false>
|
|
};
|
|
|
|
ValueMapping mg2connectedcomponents2VM [] = {
|
|
mg23connectedcomponentsVMT<Mem,MGraph2, true>,
|
|
mg23connectedcomponentsVMT<MPointer,MGraph2, true>
|
|
};
|
|
|
|
ValueMapping mg3connectedcomponents2VM [] = {
|
|
mg23connectedcomponentsVMT<Mem,MGraph3, true>,
|
|
mg23connectedcomponentsVMT<MPointer,MGraph3, true>
|
|
};
|
|
|
|
|
|
OperatorSpec mg23connctedcomponentsSpec(
|
|
"mgraph{2,3} -> stream(tuple)",
|
|
"mgconnectedcomponents(_)",
|
|
"Append a component number to the graph edges",
|
|
"query mgconnectedcomponents(mg2)"
|
|
);
|
|
|
|
Operator mg2connectedcomponentsOp(
|
|
"mg2connectedcomponents",
|
|
mg23connctedcomponentsSpec.getStr(),
|
|
2,
|
|
mg2connectedcomponentsVM,
|
|
mg23connectedcomponentsSelect,
|
|
mg23connectedcomponentsTM<MGraph2,false>
|
|
);
|
|
|
|
Operator mg3connectedcomponentsOp(
|
|
"mg3connectedcomponents",
|
|
mg23connctedcomponentsSpec.getStr(),
|
|
2,
|
|
mg3connectedcomponentsVM,
|
|
mg23connectedcomponentsSelect,
|
|
mg23connectedcomponentsTM<MGraph3,false>
|
|
);
|
|
|
|
|
|
OperatorSpec mg23connctedcomponentsNSpec(
|
|
"mgraph{2,3} -> stream(tuple)",
|
|
"mgconnectedcomponents(_)",
|
|
"Append a component number to the graph nodes",
|
|
"query graph23 mgXconnectedcomponentsN count"
|
|
);
|
|
|
|
|
|
Operator mg2connectedcomponentsNOp(
|
|
"mg2connectedcomponentsN",
|
|
mg23connctedcomponentsNSpec.getStr(),
|
|
2,
|
|
mg2connectedcomponents2VM,
|
|
mg23connectedcomponentsSelect,
|
|
mg23connectedcomponentsTM<MGraph2,true>
|
|
);
|
|
|
|
Operator mg3connectedcomponentsNOp(
|
|
"mg3connectedcomponentsN",
|
|
mg23connctedcomponentsNSpec.getStr(),
|
|
2,
|
|
mg3connectedcomponents2VM,
|
|
mg23connectedcomponentsSelect,
|
|
mg23connectedcomponentsTM<MGraph3,true>
|
|
);
|
|
|
|
|
|
/*
|
|
~ Computing contraction ~
|
|
|
|
*/
|
|
template<class G, bool onlySize>
|
|
ListExpr mgcontractTM(ListExpr args){
|
|
if(!nl->HasLength(args,8)){
|
|
return listutils::typeError("8 arguments expected");
|
|
}
|
|
ListExpr graph;
|
|
if(!getMemSubType(nl->First(args),graph)){
|
|
return listutils::typeError("first arg is not a memory object");
|
|
}
|
|
if(!G::checkType(graph)){
|
|
return listutils::typeError("argument not of type " + G::BasicType());
|
|
}
|
|
|
|
if(!CcInt::checkType(nl->Second(args))){
|
|
return listutils::typeError("expected graph x int^7");
|
|
}
|
|
if(!CcInt::checkType(nl->Third(args))){
|
|
return listutils::typeError("expected graph x int^7");
|
|
}
|
|
if(!CcInt::checkType(nl->Fourth(args))){
|
|
return listutils::typeError("expected graph x int^7");
|
|
}
|
|
if(!CcInt::checkType(nl->Fifth(args))){
|
|
return listutils::typeError("expected graph x int^7");
|
|
}
|
|
if(!CcInt::checkType(nl->Sixth(args))){
|
|
return listutils::typeError("expected graph x int^7");
|
|
}
|
|
if(!CcInt::checkType(nl->Sixth(nl->Rest(args)))){
|
|
return listutils::typeError("expected graph x int^7");
|
|
}
|
|
if(!CcInt::checkType(nl->Sixth(nl->Rest(nl->Rest(args))))){
|
|
return listutils::typeError("expected graph x int^7");
|
|
}
|
|
if(onlySize){
|
|
return listutils::basicSymbol<CcInt>();
|
|
}
|
|
}
|
|
|
|
|
|
template<class GN, class Graph>
|
|
int mgcontractVMT(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
|
|
result = qp->ResultStorage(s);
|
|
CcInt* res = (CcInt*) result.addr;
|
|
Graph* g = getMemObject<Graph>((GN*) args[0].addr);
|
|
if(!g){
|
|
res->SetDefined(false);
|
|
return 0;
|
|
}
|
|
int maxPrio = 30;
|
|
CcInt* V = (CcInt*) args[1].addr;
|
|
if(V->IsDefined()){
|
|
maxPrio = V->GetValue();
|
|
}
|
|
int minBlockSize = 100;
|
|
V = (CcInt*) args[2].addr;
|
|
if(V->IsDefined()){
|
|
minBlockSize = V->GetValue();
|
|
if(minBlockSize<1) minBlockSize = 1;
|
|
}
|
|
int maxHopsF = 4;
|
|
V = (CcInt*) args[3].addr;
|
|
if(V->IsDefined()){
|
|
maxHopsF = V->GetValue();
|
|
if(maxHopsF<1) maxHopsF = 1;
|
|
}
|
|
int maxHopsB = 0;
|
|
V = (CcInt*) args[4].addr;
|
|
if(V->IsDefined()){
|
|
maxHopsB = V->GetValue();
|
|
}
|
|
int variant = 1;
|
|
V = (CcInt*) args[5].addr;
|
|
if(V->IsDefined()){
|
|
variant = V->GetValue();
|
|
}
|
|
if( (variant !=1) && (variant!=2)){
|
|
res->SetDefined(false);
|
|
return 0;
|
|
}
|
|
int skipReinsert = 0;
|
|
V = (CcInt*) args[6].addr;
|
|
if(V->IsDefined()){
|
|
skipReinsert = V->GetValue();
|
|
if(skipReinsert<0) skipReinsert=0;
|
|
}
|
|
size_t maxEdges = std::numeric_limits<size_t>::max();
|
|
V = (CcInt*) args[7].addr;
|
|
if(V->IsDefined()){
|
|
int e = V->GetValue();
|
|
if(e>0) maxEdges = e;
|
|
}
|
|
|
|
|
|
|
|
std::vector<shortCutInfo> shortcuts;
|
|
res->Set(true, g->contract(maxPrio, minBlockSize, maxHopsF,
|
|
maxHopsB,shortcuts,variant,
|
|
skipReinsert, maxEdges));
|
|
return 0;
|
|
}
|
|
|
|
ValueMapping mg2contractVM[] = {
|
|
mgcontractVMT<Mem, MGraph2>,
|
|
mgcontractVMT<MPointer, MGraph2>
|
|
};
|
|
|
|
ValueMapping mg3contractVM[] = {
|
|
mgcontractVMT<Mem, MGraph3>,
|
|
mgcontractVMT<MPointer, MGraph3>
|
|
};
|
|
|
|
int mgcontractSelect(ListExpr args){
|
|
return Mem::checkType(nl->First(args))?0:1;
|
|
}
|
|
|
|
OperatorSpec mg2contractSpec(
|
|
"MGRAPH2 x int x int x int x int x int x int x int -> int",
|
|
"mg2contract(graph, maxPrio, minBlockSIze, maxHopsF, maxHopsB, "
|
|
"variant, skipReinsert, maxEdges)",
|
|
"Computes the number of contraction edges created during contraction "
|
|
"of a graph. \n"
|
|
"graph : the graph to contract\n"
|
|
"maxPrio : do not reorganize the queue until maxPrio is reached\n"
|
|
"minBlockSize: do not reorganize the queue until minBlocksize nodes "
|
|
"have been contracted\n"
|
|
"maxHopsF : maximum number of hops (forward) for searching shortest paths\n"
|
|
"maxHopsB : maximum number of hops for backward search. If <=0, the "
|
|
"multitarget variant is used\n"
|
|
"variant: 1 - two step variant as in ContractN, 2 - use EdgeDifference "
|
|
"in single step\n"
|
|
"skipReinsert: if the queue is smaller than this value, reinsertion of "
|
|
"nodes into the queue is omitted\n"
|
|
"maxEdges : maximum number of edges for a single shortest path search.",
|
|
"query mg2contract(g2,20,800,3,1,2)"
|
|
);
|
|
|
|
OperatorSpec mg3contractSpec(
|
|
"MGRAPH3 x int x int x int x int x int x int x int -> int",
|
|
"mg3contract(graph, maxPrio, minBlockSIze, maxHopsF, maxHopsB, "
|
|
"variant, skipReinsert, maxEdges)",
|
|
"Computes the number of contraction edges created during contraction "
|
|
"of a graph. \n"
|
|
"graph : the graph to contract\n"
|
|
"maxPrio : do not reorganize the queue until maxPrio is reached\n"
|
|
"minBlockSize: do not reorganize the queue until minBlocksize nodes "
|
|
"have been contracted\n"
|
|
"maxHopsF : maximum number of hops (forward) for searching shortest paths\n"
|
|
"maxHopsB : maximum number of hops for backward search. If <=0, the "
|
|
"multitarget variant is used\n"
|
|
"variant: 1 - two step variant as in ContractN, 3 - use EdgeDifference "
|
|
"in single step\n"
|
|
"skipReinsert: if the queue is smaller than this value, reinsertion of "
|
|
"nodes into the queue is omitted"
|
|
"maxEdges : maximum number of edges for a single shortest path search.",
|
|
"query mg3contract(g3,30,800,3,1,3)"
|
|
);
|
|
|
|
Operator mg2contractOp(
|
|
"mg2contract",
|
|
mg2contractSpec.getStr(),
|
|
2,
|
|
mg2contractVM,
|
|
mgcontractSelect,
|
|
mgcontractTM<MGraph2, true>
|
|
);
|
|
|
|
Operator mg3contractOp(
|
|
"mg3contract",
|
|
mg3contractSpec.getStr(),
|
|
2,
|
|
mg3contractVM,
|
|
mgcontractSelect,
|
|
mgcontractTM<MGraph3,true>
|
|
);
|
|
|
|
|
|
/*
|
|
Operator minPathCosts for mgraph2 and mgraph3
|
|
|
|
*/
|
|
template<class G>
|
|
ListExpr mgminPathCostTM(ListExpr args){
|
|
if(!nl->HasLength(args,5) && !nl->HasLength(args,7)){
|
|
return listutils::typeError("5 arguments expected");
|
|
}
|
|
ListExpr graph;
|
|
if(!getMemSubType(nl->First(args),graph)){
|
|
return listutils::typeError("first argument is not a memory object");
|
|
}
|
|
if(!G::checkType(graph)){
|
|
return listutils::typeError("argument not of type " + G::BasicType());
|
|
}
|
|
|
|
if(!CcInt::checkType(nl->Second(args))){
|
|
return listutils::typeError("expected graph x int x int x int 2");
|
|
}
|
|
if(!CcInt::checkType(nl->Third(args))){
|
|
return listutils::typeError("expected graph x int x int x int 3");
|
|
}
|
|
if(!CcInt::checkType(nl->Fourth(args))){
|
|
return listutils::typeError("expected graph x int x int x int 4");
|
|
}
|
|
if(!CcInt::checkType(nl->Fifth(args))){
|
|
return listutils::typeError("expected graph x int x int x int 5");
|
|
}
|
|
if(nl->HasLength(args,5)){
|
|
return nl->ThreeElemList( nl->SymbolAtom(Symbols::APPEND()),
|
|
nl->TwoElemList(nl->IntAtom(-1), nl->RealAtom(0)),
|
|
listutils::basicSymbol<CcReal>());
|
|
}
|
|
if(!CcInt::checkType(nl->Sixth(args))){
|
|
return listutils::typeError("expected graph x int x int x int 6");
|
|
}
|
|
if(!CcReal::checkType(nl->Sixth(nl->Rest(args)))){
|
|
return listutils::typeError("maxCosts not of type real");
|
|
}
|
|
return listutils::basicSymbol<CcReal>();
|
|
}
|
|
|
|
|
|
template<class GN, class Graph>
|
|
int mgminPathCostVMT(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
|
|
result = qp->ResultStorage(s);
|
|
CcReal* res = (CcReal*) result.addr;
|
|
Graph* g = getMemObject<Graph>((GN*) args[0].addr);
|
|
if(!g){
|
|
res->SetDefined(false);
|
|
return 0;
|
|
}
|
|
int source = 0;
|
|
CcInt* V = (CcInt*) args[1].addr;
|
|
if(V->IsDefined()){
|
|
source = V->GetValue();
|
|
}
|
|
int target = 1;
|
|
V = (CcInt*) args[2].addr;
|
|
if(V->IsDefined()){
|
|
target = V->GetValue();
|
|
}
|
|
int maxHopsForward = 4;
|
|
V = (CcInt*) args[3].addr;
|
|
if(V->IsDefined()){
|
|
maxHopsForward = V->GetValue();
|
|
}
|
|
int maxHopsBackward = 4;
|
|
V = (CcInt*) args[4].addr;
|
|
if(V->IsDefined()){
|
|
maxHopsBackward = V->GetValue();
|
|
}
|
|
int forbidden = -1;
|
|
V = (CcInt*) args[5].addr;
|
|
if(V->IsDefined()){
|
|
forbidden = V->GetValue();
|
|
}
|
|
double maxCosts = 0;
|
|
CcReal* CV = (CcReal*) args[6].addr;
|
|
if(CV->IsDefined()){
|
|
maxCosts = CV->GetValue();
|
|
}
|
|
|
|
|
|
res->Set(true, g->pathCosts(source, target, maxHopsForward,
|
|
maxHopsBackward,forbidden, maxCosts));
|
|
return 0;
|
|
}
|
|
|
|
ValueMapping mg2minPathCostVM[] = {
|
|
mgminPathCostVMT<Mem, MGraph2>,
|
|
mgminPathCostVMT<MPointer, MGraph2>
|
|
};
|
|
|
|
ValueMapping mg3minPathCostVM[] = {
|
|
mgminPathCostVMT<Mem, MGraph3>,
|
|
mgminPathCostVMT<MPointer, MGraph3>
|
|
};
|
|
|
|
int mgminPathCostSelect(ListExpr args){
|
|
return Mem::checkType(nl->First(args))?0:1;
|
|
}
|
|
|
|
OperatorSpec mg2minPathCostSpec(
|
|
"MGRAPH2 x int x int x int x int [x int x real] -> real",
|
|
"mg2minpathcists(graph, source, target, maxHopsForward, maxHopsBackward)"
|
|
" [, forbidden, maxCosts]",
|
|
"Comutes the minimum path length from source to target using a "
|
|
"maximum number of hops in each direction",
|
|
"query mg2minPathCost(g2, 1,42,10,10)"
|
|
);
|
|
|
|
OperatorSpec mg3minPathCostSpec(
|
|
"MGRAPH3 x int x int x int x int [x int x real] -> real",
|
|
"mg3minpathcists(graph, source, target, maxHopsForward, maxHopsBackward)"
|
|
" [, forbidden, maxCosts]",
|
|
"Comutes the minimum path length from source to target using a "
|
|
"maximum number of hops in each direction",
|
|
"query mg3minPathCost(g3, 1,42,10,10)"
|
|
);
|
|
|
|
Operator mg2minPathCostOp(
|
|
"mg2minPathCost",
|
|
mg2minPathCostSpec.getStr(),
|
|
2,
|
|
mg2minPathCostVM,
|
|
mgminPathCostSelect,
|
|
mgminPathCostTM<MGraph2>
|
|
);
|
|
|
|
Operator mg3minPathCostOp(
|
|
"mg3minPathCost",
|
|
mg3minPathCostSpec.getStr(),
|
|
2,
|
|
mg3minPathCostVM,
|
|
mgminPathCostSelect,
|
|
mgminPathCostTM<MGraph3>
|
|
);
|
|
|
|
/*
|
|
2.4 exportddsg
|
|
|
|
*/
|
|
template<class G>
|
|
ListExpr exportddsgTM(ListExpr args){
|
|
if(!nl->HasLength(args,3)){
|
|
return listutils::typeError("three arguments expected");
|
|
}
|
|
ListExpr graph;
|
|
if(!getMemSubType(nl->First(args), graph)){
|
|
return listutils::typeError("first arg is not a memory object");
|
|
}
|
|
if(!G::checkType(graph)){
|
|
return listutils::typeError("argument not of type " + G::BasicType());
|
|
}
|
|
ListExpr fn = nl->Second(args);
|
|
if(!FText::checkType(fn) && !CcString::checkType(fn)){
|
|
return listutils::typeError("expected text or string as second argument");
|
|
}
|
|
ListExpr scale = nl->Third(args);
|
|
if(!CcInt::checkType(scale) && !CcReal::checkType(scale)){
|
|
return listutils::typeError("expected int or real as third argument");
|
|
}
|
|
return listutils::basicSymbol<CcBool>();
|
|
}
|
|
|
|
|
|
template<class GN, class FN, class SF, class Graph>
|
|
int exportddsgVMT(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
|
|
result = qp->ResultStorage(s);
|
|
CcBool* res = (CcBool*) result.addr;
|
|
Graph* g = getMemObject<Graph>((GN*) args[0].addr);
|
|
FN* fileName = (FN*) args[1].addr;
|
|
SF* scaleFactor = (SF*) args[2].addr;
|
|
if(!g || !fileName->IsDefined() || !scaleFactor->IsDefined()){
|
|
res->SetDefined(false);
|
|
return 0;
|
|
}
|
|
string fn = fileName->GetValue();
|
|
double sf = scaleFactor->GetValue();
|
|
if(sf<=0){
|
|
res->Set(true,false);
|
|
return 0;
|
|
}
|
|
res->Set(true,g->exportDDSG(fn,sf));
|
|
return 0;
|
|
}
|
|
|
|
ValueMapping mg2exportddsgVM[] = {
|
|
exportddsgVMT<Mem, CcString, CcInt, MGraph2>,
|
|
exportddsgVMT<Mem, CcString, CcReal, MGraph2>,
|
|
exportddsgVMT<Mem, FText, CcInt, MGraph2>,
|
|
exportddsgVMT<Mem, FText, CcReal, MGraph2>,
|
|
|
|
exportddsgVMT<MPointer, CcString, CcInt, MGraph2>,
|
|
exportddsgVMT<MPointer, CcString, CcReal, MGraph2>,
|
|
exportddsgVMT<MPointer, FText, CcInt, MGraph2>,
|
|
exportddsgVMT<MPointer, FText, CcReal, MGraph2>
|
|
};
|
|
|
|
ValueMapping mg3exportddsgVM[] = {
|
|
exportddsgVMT<Mem, CcString, CcInt, MGraph3>,
|
|
exportddsgVMT<Mem, CcString, CcReal, MGraph3>,
|
|
exportddsgVMT<Mem, FText, CcInt, MGraph3>,
|
|
exportddsgVMT<Mem, FText, CcReal, MGraph3>,
|
|
|
|
exportddsgVMT<MPointer, CcString, CcInt, MGraph3>,
|
|
exportddsgVMT<MPointer, CcString, CcReal, MGraph3>,
|
|
exportddsgVMT<MPointer, FText, CcInt, MGraph3>,
|
|
exportddsgVMT<MPointer, FText, CcReal, MGraph3>
|
|
};
|
|
|
|
int exportddsgSelect(ListExpr args){
|
|
int n1 = Mem::checkType(nl->First(args))?0:4;
|
|
int n2 = CcString::checkType(nl->Second(args))?0:2;
|
|
int n3 = CcInt::checkType(nl->Third(args))?0:1;
|
|
return n1+n2+n3;
|
|
}
|
|
|
|
OperatorSpec mg2exportddsgSpec(
|
|
"MGRAPH2 x {string,text} x {int,real} -> bool",
|
|
"graph mg2exportddsg[filename, scalefactor] ",
|
|
"Export an mgraph2 to a file using the ddsg format. "
|
|
"DDSG supports only integers as costs. All costs in the "
|
|
"graph a multiplied with the scale factor and rounded "
|
|
" to the next integer value. "
|
|
"The return value gives the success of this operation.",
|
|
"query mg2 exportddsg['graph.txt', 1000]"
|
|
);
|
|
|
|
OperatorSpec mg3exportddsgSpec(
|
|
"MGRAPH3 x {string,text} x {int,real} -> bool",
|
|
"graph mg3exportddsg[filename, scalefactor] ",
|
|
"Export an mgraph3 to a file using the ddsg format. "
|
|
"DDSG supports only integers as costs. All costs in the "
|
|
"graph a multiplied with the scale factor and rounded "
|
|
" to the next integer value. "
|
|
"The return value gives the success of this operation.",
|
|
"query mg3 exportddsg['graph.txt', 1000]"
|
|
);
|
|
|
|
Operator mg2exportddsgOp(
|
|
"mg2exportddsg",
|
|
mg2exportddsgSpec.getStr(),
|
|
8,
|
|
mg2exportddsgVM,
|
|
exportddsgSelect,
|
|
exportddsgTM<MGraph2>
|
|
);
|
|
|
|
Operator mg3exportddsgOp(
|
|
"mg3exportddsg",
|
|
mg3exportddsgSpec.getStr(),
|
|
8,
|
|
mg3exportddsgVM,
|
|
exportddsgSelect,
|
|
exportddsgTM<MGraph3>
|
|
);
|
|
|
|
|
|
/*
|
|
mgraphPrint
|
|
|
|
*/
|
|
ListExpr mgraphPrintTM(ListExpr args){
|
|
if(!nl->HasLength(args,3)){
|
|
return listutils::typeError("three argument expected");
|
|
}
|
|
ListExpr graph;
|
|
if(!getMemSubType(nl->First(args), graph)){
|
|
return listutils::typeError("first arg is not a memory object");
|
|
}
|
|
if(!MGraph2::checkType(graph) && !MGraph3::checkType(graph)){
|
|
return listutils::typeError("argument not of type mgraph2 or mgraph3");
|
|
}
|
|
if(!CcBool::checkType(nl->Second(args))){
|
|
return listutils::typeError("second arg not of type bool");
|
|
}
|
|
if(!CcBool::checkType(nl->Third(args))){
|
|
return listutils::typeError("third arg not of type bool");
|
|
}
|
|
return listutils::basicSymbol<CcBool>();
|
|
}
|
|
|
|
template< class GN>
|
|
int mgraphPrintVMT(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
|
|
MGraphCommon* g = getMemObject2<MGraphCommon>((GN*) args[0].addr);
|
|
CcBool* printInfo = (CcBool*) args[1].addr;
|
|
CcBool* printBackward = (CcBool*) args[2].addr;
|
|
result = qp->ResultStorage(s);
|
|
CcBool* res = (CcBool*) result.addr;
|
|
if(!printInfo->IsDefined() || !printBackward->IsDefined()){
|
|
res->SetDefined(false);
|
|
return 0;
|
|
}
|
|
res->Set(true,true);
|
|
std::vector<std::string>* names = nullptr;
|
|
if(printInfo->GetValue()){
|
|
ListExpr gT = qp->GetType(qp->GetSon(s,0));
|
|
if(nl->HasLength(gT,2) && nl->IsEqual(nl->First(gT),MPointer::BasicType())){
|
|
gT = nl->Second(gT);
|
|
} // remove potential mpointer
|
|
if(nl->HasLength(gT,2) && nl->IsEqual(nl->First(gT),Mem::BasicType())){
|
|
gT = nl->Second(gT);
|
|
} // remove mem
|
|
if(nl->HasLength(gT,2) ){
|
|
gT = nl->Second(gT);
|
|
} // remove mgraphX -> tupleType left
|
|
|
|
names = new std::vector<std::string>(Tuple::getAttrNames(gT));
|
|
// bring all names to the same length
|
|
size_t m=0;
|
|
for(size_t i=0;i<names->size();i++){
|
|
if(m< (*names)[i].length()) m = (*names)[i].length();
|
|
}
|
|
for(size_t i=0;i<names->size();i++){
|
|
while((*names)[i].length() < m){
|
|
(*names)[i] += " ";
|
|
}
|
|
}
|
|
}
|
|
g->print(cout, names, printBackward->GetValue());
|
|
if(names != nullptr){
|
|
delete names;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
ValueMapping mgraphPrintVM[] = {
|
|
mgraphPrintVMT<Mem>,
|
|
mgraphPrintVMT<MPointer>
|
|
};
|
|
|
|
int mgraphPrintSelect(ListExpr args){
|
|
return Mem::checkType(nl->First(args))?0:1;
|
|
}
|
|
|
|
OperatorSpec mgraphPrintSpec(
|
|
"MGRAPH x bool x bool -> bool ",
|
|
"_ mgraphPrint[_,_] ",
|
|
"Prints out the graph that is given as the first argument. "
|
|
"The second argument specifies whether the tuple info of "
|
|
" each edge should be printed out. The third argment specifies "
|
|
"whether backward edges should be printed out. ",
|
|
"query mg2 print[FALSE,FALSE] "
|
|
);
|
|
|
|
Operator mgraphPrintOp(
|
|
"mgraphPrint",
|
|
mgraphPrintSpec.getStr(),
|
|
2,
|
|
mgraphPrintVM,
|
|
mgraphPrintSelect,
|
|
mgraphPrintTM
|
|
);
|
|
|
|
|
|
/*
|
|
mgraph2text
|
|
|
|
*/
|
|
ListExpr mgraph2textTM(ListExpr args){
|
|
if(!nl->HasLength(args,3)){
|
|
return listutils::typeError("three argument expected");
|
|
}
|
|
ListExpr graph;
|
|
if(!getMemSubType(nl->First(args), graph)){
|
|
return listutils::typeError("first arg is not a memory object");
|
|
}
|
|
if(!MGraph2::checkType(graph) && !MGraph3::checkType(graph)){
|
|
return listutils::typeError("argument not of type mgraph2 or mgraph3");
|
|
}
|
|
if(!CcBool::checkType(nl->Second(args))){
|
|
return listutils::typeError("second arg not of type bool");
|
|
}
|
|
if(!CcBool::checkType(nl->Third(args))){
|
|
return listutils::typeError("third arg not of type bool");
|
|
}
|
|
return listutils::basicSymbol<FText>();
|
|
}
|
|
|
|
template< class GN>
|
|
int mgraph2textVMT(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
|
|
MGraphCommon* g = getMemObject2<MGraphCommon>((GN*) args[0].addr);
|
|
CcBool* printInfo = (CcBool*) args[1].addr;
|
|
CcBool* printBackward = (CcBool*) args[2].addr;
|
|
result = qp->ResultStorage(s);
|
|
FText* res = (FText*) result.addr;
|
|
if(!printInfo->IsDefined() || !printBackward->IsDefined()){
|
|
res->SetDefined(false);
|
|
return 0;
|
|
}
|
|
stringstream ss;
|
|
std::vector<std::string>* names = nullptr;
|
|
if(printInfo->GetValue()){
|
|
ListExpr gT = qp->GetType(qp->GetSon(s,0));
|
|
if(nl->HasLength(gT,2) && nl->IsEqual(nl->First(gT),MPointer::BasicType())){
|
|
gT = nl->Second(gT);
|
|
} // remove potential mpointer
|
|
if(nl->HasLength(gT,2) && nl->IsEqual(nl->First(gT),Mem::BasicType())){
|
|
gT = nl->Second(gT);
|
|
} // remove mem
|
|
if(nl->HasLength(gT,2) ){
|
|
gT = nl->Second(gT);
|
|
} // remove mgraphX -> tupleType left
|
|
|
|
names = new std::vector<std::string>(Tuple::getAttrNames(gT));
|
|
// bring all names to the same length
|
|
size_t m=0;
|
|
for(size_t i=0;i<names->size();i++){
|
|
if(m< (*names)[i].length()) m = (*names)[i].length();
|
|
}
|
|
for(size_t i=0;i<names->size();i++){
|
|
while((*names)[i].length() < m){
|
|
(*names)[i] += " ";
|
|
}
|
|
}
|
|
}
|
|
g->print(ss, names, printBackward->GetValue());
|
|
if(names != nullptr){
|
|
delete names;
|
|
}
|
|
res->Set(true, ss.str());
|
|
return 0;
|
|
}
|
|
|
|
ValueMapping mgraph2textVM[] = {
|
|
mgraph2textVMT<Mem>,
|
|
mgraph2textVMT<MPointer>
|
|
};
|
|
|
|
int mgraph2textSelect(ListExpr args){
|
|
return Mem::checkType(nl->First(args))?0:1;
|
|
}
|
|
|
|
OperatorSpec mgraph2textSpec(
|
|
"MGRAPH x bool x bool -> bool ",
|
|
"_ mgraph2text[_,_] ",
|
|
"Converts a main memory grapg to a text. "
|
|
"The second argument specifies whether the tuple info of "
|
|
" each edge should be part of the result. The third argment specifies "
|
|
"whether backward edges should be in the result. ",
|
|
"query mgraph2text[FALSE,FALSE] "
|
|
);
|
|
|
|
Operator mgraph2textOp(
|
|
"mgraph2text",
|
|
mgraph2textSpec.getStr(),
|
|
2,
|
|
mgraph2textVM,
|
|
mgraph2textSelect,
|
|
mgraph2textTM
|
|
);
|
|
|
|
|
|
ListExpr MGroupTM(ListExpr args)
|
|
{
|
|
if(nl->ListLength(args)<1){
|
|
ErrorReporter::ReportError("one argument expected");
|
|
return nl->TypeError();
|
|
}
|
|
|
|
ListExpr first = nl->First(args);
|
|
|
|
if(!Stream<Tuple>::checkType(first)){
|
|
return listutils::typeError("tuple stream expected");
|
|
}
|
|
|
|
ListExpr relType = nl->TwoElemList( listutils::basicSymbol<Relation>(),
|
|
nl->Second(first));
|
|
return MPointer::wrapType(Mem::wrapType(relType));
|
|
|
|
}
|
|
/*
|
|
2.3.2 Specification of operator ~MGroup~
|
|
|
|
*/
|
|
const string MGroupSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
|
"\"Remarks\" ) "
|
|
"( <text>((stream x)) -> (mem (rel x))</text--->"
|
|
"<text>type operator</text--->"
|
|
"<text>Maps stream type to a mem rel.</text--->"
|
|
"<text>not for use with sos-syntax</text--->"
|
|
") )";
|
|
|
|
|
|
|
|
|
|
/*
|
|
2.3.3 Definition of operator ~group~
|
|
|
|
*/
|
|
Operator mgroupOp (
|
|
"MGROUP", // name
|
|
MGroupSpec, // specification
|
|
0, // no value mapping
|
|
Operator::SimpleSelect, // trivial selection function
|
|
MGroupTM // type mapping
|
|
);
|
|
|
|
|
|
|
|
|
|
/*
|
|
Operator memgroupby
|
|
|
|
*/
|
|
ListExpr memgroupbyTM(ListExpr args){
|
|
|
|
if(!nl->HasLength(args,3)){
|
|
return listutils::typeError("stream x attrlist x funlist expected");
|
|
}
|
|
if(!Stream<Tuple>::checkType(nl->First(args))){
|
|
return listutils::typeError("first arg is not a tuple stream");
|
|
}
|
|
if(nl->AtomType(nl->Second(args))!=NoAtom){
|
|
return listutils::typeError("second arg is not a list of attributes");
|
|
}
|
|
if(nl->AtomType(nl->Third(args))!=NoAtom){
|
|
return listutils::typeError("third arg is not a list of functions");
|
|
}
|
|
vector<int> groupAttr;
|
|
vector<ListExpr> groupTypes;
|
|
vector<string> groupNames;
|
|
ListExpr attrList = nl->Second(nl->Second(nl->First(args)));
|
|
ListExpr groupAttrList = nl->Second(args);
|
|
while(!nl->IsEmpty( groupAttrList)){
|
|
ListExpr ga = nl->First(groupAttrList);
|
|
groupAttrList = nl->Rest(groupAttrList);
|
|
if(nl->AtomType(ga)!=SymbolType){
|
|
return listutils::typeError("Invalid attr ID in attr list");
|
|
}
|
|
string aname = nl->SymbolValue(ga);
|
|
ListExpr at;
|
|
int index = listutils::findAttribute(attrList, aname, at);
|
|
if(!index){
|
|
return listutils::typeError("attribute " + aname
|
|
+ " not part of the incoming stream");
|
|
}
|
|
groupAttr.push_back(index - 1);
|
|
groupTypes.push_back(at);
|
|
groupNames.push_back(aname);
|
|
}
|
|
|
|
|
|
ListExpr reltype = nl->TwoElemList(
|
|
listutils::basicSymbol<Relation>(),
|
|
nl->Second(nl->First(args)));
|
|
|
|
ListExpr funarg = MPointer::wrapType(Mem::wrapType(reltype));
|
|
|
|
// check funtion list
|
|
ListExpr funlist = nl->Third(args);
|
|
while(!nl->IsEmpty(funlist)){
|
|
ListExpr nfun = nl->First(funlist);
|
|
funlist = nl->Rest(funlist);
|
|
if(!nl->HasLength(nfun,2)){
|
|
return listutils::typeError("found problem in function list");
|
|
}
|
|
ListExpr aname = nl->First(nfun);
|
|
string err;
|
|
if(!listutils::isValidAttributeName(aname, err)){
|
|
return listutils::typeError("invalid attr name " + err);
|
|
}
|
|
ListExpr fun = nl->Second(nfun);
|
|
if(!listutils::isMap<1>(fun)){
|
|
return listutils::typeError("found something that is not "
|
|
"an unary function");
|
|
}
|
|
if(!nl->Equal(funarg, nl->Second(fun))){
|
|
return listutils::typeError("invalid function argument");
|
|
}
|
|
if(!Attribute::checkType(nl->Third(fun))){
|
|
return listutils::typeError("function result is not an attribute");
|
|
}
|
|
groupNames.push_back(nl->SymbolValue(aname));
|
|
groupTypes.push_back(nl->Third(fun));
|
|
}
|
|
|
|
if(groupNames.empty()){
|
|
return listutils::typeError("grouping attributes and functions are empty");
|
|
}
|
|
assert(groupNames.size() == groupTypes.size());
|
|
|
|
ListExpr resAttrList = nl->OneElemList(
|
|
nl->TwoElemList(nl->SymbolAtom(groupNames[0]),
|
|
groupTypes[0]));
|
|
ListExpr last = resAttrList;
|
|
for(size_t i=1;i<groupNames.size();i++){
|
|
last = nl->Append(last, nl->TwoElemList(nl->SymbolAtom(groupNames[i]),
|
|
groupTypes[i]));
|
|
}
|
|
ListExpr resType = nl->TwoElemList(
|
|
listutils::basicSymbol<Stream<Tuple> >(),
|
|
nl->TwoElemList(
|
|
listutils::basicSymbol<Tuple>(),
|
|
resAttrList));
|
|
|
|
|
|
|
|
if(groupAttr.empty()){
|
|
return resType;
|
|
}
|
|
|
|
ListExpr appendList = nl->OneElemList( nl->IntAtom(groupAttr[0]));
|
|
last = appendList;
|
|
for(size_t i=1;i<groupAttr.size();i++){
|
|
last = nl->Append(last, nl->IntAtom(groupAttr[i]));
|
|
}
|
|
|
|
|
|
ListExpr r = nl->ThreeElemList(
|
|
nl->SymbolAtom(Symbols::APPEND()),
|
|
appendList,
|
|
resType);
|
|
return r;
|
|
}
|
|
|
|
|
|
class memgroupbyLocalInfo{
|
|
public:
|
|
|
|
memgroupbyLocalInfo(Word _stream,
|
|
vector<int>* _groupAttr,
|
|
vector<Supplier>* _funs,
|
|
vector<ArgVectorPointer>* _funargs,
|
|
TupleType* _tt): stream(_stream),
|
|
groupAttr(_groupAttr), funs(_funs),
|
|
funargs(_funargs), tt(_tt) {
|
|
tt->IncReference();
|
|
stream.open();
|
|
start = stream.request();
|
|
mrel = new MemoryRelObject();
|
|
mp = new MPointer(mrel,true);
|
|
}
|
|
|
|
~memgroupbyLocalInfo(){
|
|
tt->DeleteIfAllowed();
|
|
stream.close();
|
|
delete mp; // mrel is deleted automatically
|
|
}
|
|
|
|
Tuple* next() {
|
|
if(!start){
|
|
return 0;
|
|
}
|
|
updateMRel();
|
|
return createResultTuple();
|
|
}
|
|
|
|
|
|
private:
|
|
Stream<Tuple> stream;
|
|
vector<int>* groupAttr;
|
|
vector<Supplier>* funs;
|
|
vector<ArgVectorPointer>* funargs;
|
|
TupleType* tt;
|
|
Tuple* start;
|
|
MemoryRelObject* mrel; // represents the current group
|
|
MPointer* mp;
|
|
Word funres;
|
|
|
|
|
|
bool matches(Tuple* tuple){
|
|
for(size_t i=0;i<groupAttr->size();i++){
|
|
int a = (*groupAttr)[i];
|
|
Attribute* a1 = start->GetAttribute(a);
|
|
Attribute* a2 = tuple->GetAttribute(a);
|
|
if(a1->Compare(a2)!=0){
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void updateMRel(){
|
|
mrel->clear();
|
|
mrel->addTuple(start);
|
|
Tuple* tuple;
|
|
while( (tuple=stream.request())){
|
|
if(matches(tuple)){
|
|
mrel->addTuple(tuple);
|
|
} else {
|
|
start = tuple;
|
|
return;
|
|
}
|
|
}
|
|
start = 0;
|
|
}
|
|
|
|
Tuple* createResultTuple(){
|
|
vector<Tuple*>* rel = mrel->getmmrel();
|
|
assert(rel->size()>0);
|
|
|
|
Tuple* t1 = (*rel)[0];
|
|
Tuple* res = new Tuple(tt);
|
|
// copy group attributes
|
|
for(size_t i=0;i<groupAttr->size();i++){
|
|
res->CopyAttribute((*groupAttr)[i],t1,i);
|
|
}
|
|
// append the function results
|
|
int n1 = groupAttr->size();
|
|
for(size_t i=0;i<funs->size();i++){
|
|
ArgVectorPointer avp = (*funargs)[i];
|
|
((*avp)[0]).setAddr(mp);
|
|
Supplier fun = (*funs)[i];
|
|
qp->Request(fun, funres);
|
|
res->PutAttribute(n1+i, ((Attribute*)funres.addr)->Clone());
|
|
}
|
|
|
|
return res;
|
|
}
|
|
};
|
|
|
|
|
|
struct memgroupbyGlobalInfo{
|
|
TupleType* tt;
|
|
vector<int> groupAttr;
|
|
vector<Supplier> funs;
|
|
vector<ArgVectorPointer> funargs;
|
|
};
|
|
|
|
int memgroupbyVM(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
|
|
memgroupbyLocalInfo* li = (memgroupbyLocalInfo*) local.addr;
|
|
memgroupbyGlobalInfo* gi = (memgroupbyGlobalInfo*) qp->GetLocal2(s).addr;
|
|
|
|
switch(message){
|
|
case INIT:{
|
|
return 0;
|
|
}
|
|
|
|
case FINISH: {
|
|
if(gi){
|
|
gi->tt->DeleteIfAllowed();
|
|
delete gi;
|
|
qp->GetLocal2(s).addr=0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
case OPEN:{
|
|
if(!gi){
|
|
gi = new memgroupbyGlobalInfo();
|
|
gi->tt = new TupleType(nl->Second(GetTupleResultType(s)));
|
|
// collect attribute positions
|
|
for(int i=3; i<qp->GetNoSons(s);i++){
|
|
gi->groupAttr.push_back(
|
|
((CcInt*)args[i].addr)->GetValue());
|
|
}
|
|
// collect functions and theire argument vectors
|
|
Supplier funlist = qp->GetSon(s,2);
|
|
for(int i=0;i<qp->GetNoSons(funlist);i++){
|
|
Supplier namedfun = qp->GetSupplier(funlist,i);
|
|
Supplier fun = qp->GetSupplier(namedfun,1);
|
|
gi->funs.push_back(fun);
|
|
ArgVectorPointer avp = qp->Argument(fun);
|
|
gi->funargs.push_back(avp);
|
|
}
|
|
qp->GetLocal2(s).addr = gi;
|
|
|
|
}
|
|
|
|
|
|
if(li) delete li;
|
|
local.addr = new memgroupbyLocalInfo(args[0],
|
|
&(gi->groupAttr),
|
|
&(gi->funs),
|
|
&(gi->funargs),
|
|
gi->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 -1;
|
|
}
|
|
|
|
|
|
OperatorSpec memgroupbySpec(
|
|
"stream(T) x attrlist x funlist -> stream(B) ",
|
|
" _ memgroupby[_ , _ ] ",
|
|
"Groupes a sorted stream of tuples by a set of "
|
|
"attributes and extend each group by "
|
|
"evaluating functions on this group. "
|
|
"For each group, one result tuple is created",
|
|
"query plz feed sortby[PLZ] memgroupby[PLZ; C : group count] consume"
|
|
);
|
|
|
|
Operator memgroupbyOp(
|
|
"memgroupby",
|
|
memgroupbySpec.getStr(),
|
|
memgroupbyVM,
|
|
Operator::SimpleSelect,
|
|
memgroupbyTM
|
|
|
|
);
|
|
|
|
/*
|
|
2.5 Operator importCH
|
|
|
|
*/
|
|
ListExpr importCHTM(ListExpr args){
|
|
if(!nl->HasLength(args,2)){
|
|
return listutils::typeError("one argument expected");
|
|
}
|
|
if(!checkUsesArgs(args)){
|
|
return listutils::typeError("internal error");
|
|
}
|
|
|
|
ListExpr arg = nl->First(nl->First(args));
|
|
if(!FText::checkType(arg) && !CcString::checkType(arg)){
|
|
return listutils::typeError("string or text expected as first arg");
|
|
}
|
|
if(!CcBool::checkType(nl->First(nl->Second(args)))){
|
|
return listutils::typeError("second argument not of type bool");
|
|
}
|
|
ListExpr b = nl->Second(nl->Second(args));
|
|
if(nl->AtomType(b) != BoolType){
|
|
return listutils::typeError("second argument must be a constant bool");
|
|
}
|
|
ListExpr attrList;
|
|
if(nl->BoolValue(b)){
|
|
attrList = nl->TwoElemList(
|
|
nl->TwoElemList(nl->SymbolAtom("Node"),
|
|
listutils::basicSymbol<CcInt>()),
|
|
nl->TwoElemList(nl->SymbolAtom("Number"),
|
|
listutils::basicSymbol<CcInt>())
|
|
);
|
|
} else {
|
|
attrList = nl->OneElemList(
|
|
nl->TwoElemList(nl->SymbolAtom("Source"),
|
|
listutils::basicSymbol<CcInt>()));
|
|
ListExpr last = attrList;
|
|
last = nl->Append(last,
|
|
nl->TwoElemList(nl->SymbolAtom("Target"),
|
|
listutils::basicSymbol<CcInt>()));
|
|
last = nl->Append(last,
|
|
nl->TwoElemList(nl->SymbolAtom("Weight"),
|
|
listutils::basicSymbol<CcInt>()));
|
|
last = nl->Append(last,
|
|
nl->TwoElemList(nl->SymbolAtom("Middle"),
|
|
listutils::basicSymbol<CcInt>()));
|
|
last = nl->Append(last,
|
|
nl->TwoElemList(nl->SymbolAtom("Forward"),
|
|
listutils::basicSymbol<CcBool>()));
|
|
last = nl->Append(last,
|
|
nl->TwoElemList(nl->SymbolAtom("Backward"),
|
|
listutils::basicSymbol<CcBool>()));
|
|
last = nl->Append(last,
|
|
nl->TwoElemList(nl->SymbolAtom("Shortcut"),
|
|
listutils::basicSymbol<CcBool>()));
|
|
}
|
|
ListExpr res = nl->TwoElemList(
|
|
listutils::basicSymbol<Stream<Tuple> >(),
|
|
nl->TwoElemList(
|
|
listutils::basicSymbol<Tuple>(),
|
|
attrList));
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
class importCHInfo{
|
|
public:
|
|
|
|
importCHInfo(string _fn, bool _order, TupleType* _tt):
|
|
fn(_fn), order(_order), tt(_tt){
|
|
tt->IncReference();
|
|
in.open(fn.c_str(), ios::in | ios::binary);
|
|
size_t buffersize = 4*1024*1024;
|
|
inbuf = new char[buffersize];
|
|
in.rdbuf()->pubsetbuf(inbuf,buffersize);
|
|
error = false;
|
|
endChecked = false;
|
|
if(!in){
|
|
error = true;
|
|
cerr << "cannot open file " << fn << endl;
|
|
return;
|
|
}
|
|
char id[4];
|
|
in.read(id,4);
|
|
if(!in){
|
|
error = true;
|
|
cerr << "cannot read id " << endl;
|
|
return;
|
|
}
|
|
if(id[0]!='C' || id[1]!='H' || id[2]!='\r' || id[3]!='\n'){
|
|
cerr << "invalid id" << endl;
|
|
error = true;
|
|
return;
|
|
}
|
|
uint32_t version;
|
|
in.read((char*)&version,4);
|
|
if(version!=1){
|
|
cerr << "invalid version" << endl;
|
|
return;
|
|
}
|
|
in.read((char*)&noNodes,4);
|
|
in.read((char*)&m1,4);
|
|
in.read((char*)&m2,4);
|
|
cout << "noNodes " << noNodes << endl;
|
|
cout << "no original edges " << m1 << endl;
|
|
cout << "no shortcut edges " << m2 << endl;
|
|
cout << "expected file size " << (4*5 + noNodes*4 + m1*16 + m2*20 + 4)
|
|
<< " bytes " << endl;
|
|
currentNode =0;
|
|
currentM1 = 0;
|
|
currentM2 = 0;
|
|
if(!order){ // ignore node level block
|
|
cout << " ignore " << (noNodes*4) << " bytes " << endl;
|
|
char* buf = new char[noNodes*4];
|
|
in.read(buf,noNodes*4);
|
|
delete[] buf;
|
|
}
|
|
|
|
}
|
|
~importCHInfo(){
|
|
in.close();
|
|
delete[] inbuf;
|
|
tt->DeleteIfAllowed();
|
|
}
|
|
|
|
Tuple* next(){
|
|
return order?nextOrder():nextEdge();
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
string fn;
|
|
bool order;
|
|
TupleType* tt;
|
|
char* inbuf;
|
|
ifstream in;
|
|
bool error;
|
|
uint32_t noNodes;
|
|
uint32_t m1;
|
|
uint32_t m2;
|
|
uint32_t currentNode;
|
|
uint32_t currentM1;
|
|
uint32_t currentM2;
|
|
bool endChecked;
|
|
|
|
Tuple* nextOrder(){
|
|
if(error) return 0;
|
|
if(!in) {
|
|
error = true;
|
|
return 0;
|
|
}
|
|
if(currentNode>=noNodes){
|
|
error = true; // not really an error
|
|
return 0;
|
|
}
|
|
uint32_t level;
|
|
in.read((char*) &level,4);
|
|
if(!in){
|
|
error = true;
|
|
return 0;
|
|
}
|
|
Tuple* res = new Tuple(tt);
|
|
res->PutAttribute(0, new CcInt(true,currentNode));
|
|
res->PutAttribute(1, new CcInt(true, level));
|
|
currentNode++;
|
|
return res;
|
|
}
|
|
|
|
Tuple* nextEdge(){
|
|
if(error) return 0;
|
|
if(currentM1>=m1 && currentM2 >= m2){
|
|
if(!endChecked){
|
|
uint32_t end;
|
|
in.read((char*)&end,4);
|
|
cout << "postion in file is " << in.tellg() << endl;
|
|
if(end!=0x12345678){
|
|
cerr << "end check failed" << endl;
|
|
cerr << "end code is " << ios::hex << end << endl;
|
|
} else {
|
|
cout << "end recognized" << endl;
|
|
}
|
|
endChecked = true;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
uint32_t source;
|
|
uint32_t target;
|
|
uint32_t weight;
|
|
uint32_t flags;
|
|
uint32_t middle1;
|
|
int middle;
|
|
in.read((char*) &source,4);
|
|
in.read((char*) &target,4);
|
|
in.read((char*) &weight,4);
|
|
in.read((char*) &flags,4);
|
|
bool shortcut = currentM1>=m1;
|
|
if(shortcut){
|
|
in.read((char*) &middle1,4);
|
|
middle = middle1;
|
|
} else {
|
|
middle = -1;
|
|
}
|
|
Tuple* res = new Tuple(tt);
|
|
res->PutAttribute(0, new CcInt(true,source));
|
|
res->PutAttribute(1, new CcInt(true,target));
|
|
res->PutAttribute(2, new CcInt(true,weight));
|
|
res->PutAttribute(3, new CcInt(true,middle));
|
|
uint32_t mask = 1;
|
|
res->PutAttribute(4, new CcBool(true, flags & mask));
|
|
mask = 2;
|
|
res->PutAttribute(5, new CcBool(true, flags & mask));
|
|
mask = 4;
|
|
res->PutAttribute(6, new CcBool(true, flags & mask));
|
|
if(shortcut){
|
|
currentM2++;
|
|
} else {
|
|
currentM1++;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
template<class F>
|
|
int importCHVMT(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
|
|
importCHInfo* li = (importCHInfo*) local.addr;
|
|
switch(message){
|
|
case OPEN: {
|
|
if(li){
|
|
delete li;
|
|
local.addr = 0;
|
|
}
|
|
F* filename = (F*) args[0].addr;
|
|
CcBool* order = (CcBool*) args[1].addr;
|
|
if(!filename->IsDefined() || !order->IsDefined()){
|
|
return 0;
|
|
}
|
|
TupleType* tt = new TupleType(nl->Second(GetTupleResultType(s)));
|
|
local.addr = new importCHInfo(filename->GetValue(), order->GetValue(), tt);
|
|
tt->DeleteIfAllowed();
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
ValueMapping importCHVM[] = {
|
|
importCHVMT<CcString>,
|
|
importCHVMT<FText>
|
|
};
|
|
|
|
int importCHSelect(ListExpr args){
|
|
return CcString::checkType(nl->First(args))?0:1;
|
|
}
|
|
|
|
OperatorSpec importCHSpec(
|
|
"{string,text} x bool -> stream(tuple)",
|
|
"importCH(fileName, onlyOrder)",
|
|
"Import a file in CH format (binary contraction hierarchie). "
|
|
"The first argument specifies the file name. If the second "
|
|
"argument is true, only the levels of the nodes are returned "
|
|
" as a tuple stream (Node : int, Level : int). "
|
|
"If this argument is set to false, the edges are returned in "
|
|
"a stream of tuple (Source : int, Target : int, Weight : int, Middle : int, "
|
|
"Forward : bool Backward : bool, Shortcut : bool).",
|
|
" query importCH('edges.hc', TRUE) count"
|
|
);
|
|
|
|
Operator importCHOp(
|
|
"importCH",
|
|
importCHSpec.getStr(),
|
|
2,
|
|
importCHVM,
|
|
importCHSelect,
|
|
importCHTM
|
|
);
|
|
|
|
|
|
|
|
/*
|
|
Operator mmergejoinproject
|
|
|
|
|
|
*/
|
|
|
|
ListExpr mmergejoinprojectTM(ListExpr args){
|
|
// rel1 x rel2 x attr1 x attr2 projectlist
|
|
if(!nl->HasLength(args,5)){
|
|
return listutils::typeError("55555 arguments expected");
|
|
}
|
|
ListExpr rel1;
|
|
if(!getMemSubType(nl->First(args),rel1)){
|
|
return listutils::typeError("first arg is not a memory object");
|
|
}
|
|
if(!Relation::checkType(rel1)){
|
|
return listutils::typeError("first arg is not a memory relation");
|
|
}
|
|
ListExpr tt1 = nl->Second(rel1);
|
|
ListExpr attrList1 = nl->Second(tt1);
|
|
|
|
// second argument: an mrel
|
|
ListExpr rel2;
|
|
if(!getMemSubType(nl->Second(args),rel2)){
|
|
return listutils::typeError("Second argument is not a memory object");
|
|
}
|
|
if(!Relation::checkType(rel2)){
|
|
return listutils::typeError("first arg is not a memory relation");
|
|
}
|
|
ListExpr tt2 = nl->Second(rel2);
|
|
ListExpr attrList2 = nl->Second(tt2);
|
|
|
|
// third argument: an attribute name of rel1
|
|
ListExpr attr1 = nl->Third(args);
|
|
if(nl->AtomType(attr1) != SymbolType){
|
|
return listutils::typeError("third arg is not a valid attribute name");
|
|
}
|
|
string attrName1 = nl->SymbolValue(attr1);
|
|
ListExpr attrType1;
|
|
int attrIndex1 = listutils::findAttribute(attrList1, attrName1, attrType1);
|
|
if(!attrIndex1){
|
|
return listutils::typeError("Attribute " + attrName1
|
|
+ " not part of the first relation");
|
|
}
|
|
// fourth argument: an attribute name of rel2
|
|
ListExpr attr2 = nl->Fourth(args);
|
|
if(nl->AtomType(attr2) != SymbolType){
|
|
return listutils::typeError("fourth arg is not a valid attribute name");
|
|
}
|
|
string attrName2 = nl->SymbolValue(attr2);
|
|
ListExpr attrType2;
|
|
int attrIndex2 = listutils::findAttribute(attrList2, attrName2, attrType2);
|
|
if(!attrIndex2){
|
|
return listutils::typeError("Attribute " + attrName2
|
|
+ " not part of the second relation");
|
|
}
|
|
// check for equal types
|
|
if(!nl->Equal(attrType1, attrType2)){
|
|
return listutils::typeError("Types of attributes " + attrName1 + " and "
|
|
+ attrName2 + " differ.");
|
|
}
|
|
// fifth argument: the projection list
|
|
ListExpr prjList = nl->Fifth(args);
|
|
if(nl->AtomType(prjList) != NoAtom){
|
|
return listutils::typeError("fifth argument must be a list "
|
|
"of attribute names");
|
|
}
|
|
ListExpr completeAttrList = listutils::concat(attrList1, attrList2);
|
|
ListExpr prjIndexes = nl->TheEmptyList();
|
|
ListExpr prjIndexesLast = nl->TheEmptyList();
|
|
ListExpr resAttrList = nl->TheEmptyList();
|
|
ListExpr resAttrListLast = nl->TheEmptyList();
|
|
bool first = true;
|
|
while(!nl->IsEmpty(prjList)){
|
|
ListExpr attr = nl->First(prjList);
|
|
prjList = nl->Rest(prjList);
|
|
if(nl->AtomType(attr)!=SymbolType){
|
|
return listutils::typeError("projection list contains an "
|
|
"invalid attribute");
|
|
}
|
|
ListExpr attrType;
|
|
string attrName = nl->SymbolValue(attr);
|
|
int attrIndex = listutils::findAttribute(completeAttrList,
|
|
attrName, attrType);
|
|
if(!attrIndex){
|
|
return listutils::typeError("attribute " + attrName
|
|
+ " not part of the relations");
|
|
}
|
|
if(first){
|
|
prjIndexes = nl->OneElemList(nl->IntAtom(attrIndex-1));
|
|
resAttrList = nl->OneElemList(nl->TwoElemList(attr, attrType));
|
|
prjIndexesLast = prjIndexes;
|
|
resAttrListLast = resAttrList;
|
|
first = false;
|
|
} else {
|
|
prjIndexesLast = nl->Append(prjIndexesLast, nl->IntAtom(attrIndex-1));
|
|
resAttrListLast = nl->Append(resAttrListLast,
|
|
nl->TwoElemList(attr, attrType));
|
|
}
|
|
}
|
|
if(!listutils::isAttrList(resAttrList)){
|
|
return listutils::typeError("There are name conflicts in projection list");
|
|
}
|
|
ListExpr resType = MPointer::wrapType(
|
|
Mem::wrapType(
|
|
nl->TwoElemList(
|
|
listutils::basicSymbol<Relation>(),
|
|
nl->TwoElemList(
|
|
listutils::basicSymbol<Tuple>(),
|
|
resAttrList))));
|
|
|
|
return nl->ThreeElemList(
|
|
nl->SymbolAtom(Symbols::APPEND()),
|
|
nl->ThreeElemList(nl->IntAtom(attrIndex1-1),
|
|
nl->IntAtom(attrIndex2-1),
|
|
prjIndexes),
|
|
resType
|
|
);
|
|
}
|
|
|
|
template<class R1, class R2>
|
|
int mmergejoinprojectVMT(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
|
|
result = qp->ResultStorage(s);
|
|
MPointer* res = (MPointer*) result.addr;
|
|
R1* r1 = (R1*) args[0].addr;
|
|
R2* r2 = (R2*) args[1].addr;
|
|
|
|
MemoryRelObject* rel1 = getMemRel(r1);
|
|
MemoryRelObject* rel2 = getMemRel(r2);
|
|
if(!rel1 || !rel2){
|
|
res->setPointer(0);
|
|
return 0;
|
|
}
|
|
// create result and insert into catalog
|
|
ListExpr resType = nl->Second(qp->GetType(s));
|
|
MemoryRelObject* resRel = new MemoryRelObject(nl->ToString(resType));
|
|
|
|
// do the join
|
|
vector<Tuple*>* v1 = rel1->getmmrel();
|
|
vector<Tuple*>* v2 = rel2->getmmrel();
|
|
|
|
size_t s1 = v1->size();
|
|
size_t s2 = v2->size();
|
|
size_t pos1 = 0;
|
|
size_t pos2 = 0;
|
|
size_t posm = 0;
|
|
|
|
int ai1 = ((CcInt*)args[5].addr)->GetValue();
|
|
int ai2 = ((CcInt*)args[6].addr)->GetValue();
|
|
|
|
vector<int> prjList;
|
|
Supplier sup2 = qp->GetSon(s,7);
|
|
for( int i=0;i<qp->GetNoSons(sup2);i++){
|
|
Word elem;
|
|
Supplier s3 = qp->GetSupplier(sup2,i);
|
|
qp->Request(s3,elem);
|
|
prjList.push_back(((CcInt*) elem.addr)->GetValue());
|
|
}
|
|
|
|
|
|
TupleType* tt = new TupleType(nl->Second(nl->Second(
|
|
nl->Second(qp->GetNumType(s)))));
|
|
|
|
while((pos1 < s1) && (pos2 < s2)){
|
|
Tuple* t1 = v1->at(pos1);
|
|
Tuple* t2 = v2->at(pos2);
|
|
if(!t1){
|
|
pos1++;
|
|
} else if(!t2){
|
|
pos2++;
|
|
} else {
|
|
Attribute* a1 = t1->GetAttribute(ai1);
|
|
Attribute* a2 = t2->GetAttribute(ai2);
|
|
int cmp = a1->Compare(a2);
|
|
if(cmp < 0){
|
|
pos1++;
|
|
} else if(cmp>0){
|
|
pos2++;
|
|
} else {
|
|
// we scan v2 until the attribute is bigger or v2 is finished
|
|
// after that, we reset pos2 and increase
|
|
posm = pos2;
|
|
while(pos2 < s2 && cmp==0){
|
|
// create result tuple
|
|
Tuple* rt = new Tuple(tt);
|
|
for(size_t i=0;i<prjList.size();i++){
|
|
int a = prjList[i];
|
|
if(a< t1->GetNoAttributes()){
|
|
rt->CopyAttribute(a,t1,i);
|
|
} else {
|
|
a = a - t1->GetNoAttributes();
|
|
rt->CopyAttribute(a,t2,i);
|
|
}
|
|
}
|
|
resRel->addTuple(rt);
|
|
// next undeleted tuple
|
|
pos2++;
|
|
while( (pos2<s2) && ( (t2 = v2->at(pos2))==0)){
|
|
pos2++;
|
|
}
|
|
if(pos2 < s2){
|
|
a2 = t2->GetAttribute(ai2);
|
|
cmp = a1->Compare(a2);
|
|
}
|
|
}
|
|
pos2 = posm;
|
|
pos1++;
|
|
}
|
|
}
|
|
}
|
|
tt->DeleteIfAllowed();
|
|
res->setPointer(resRel);
|
|
resRel->deleteIfAllowed();
|
|
return 0;
|
|
}
|
|
|
|
ValueMapping mmergejoinprojectVM[] = {
|
|
mmergejoinprojectVMT<Mem,Mem>,
|
|
mmergejoinprojectVMT<Mem,MPointer>,
|
|
mmergejoinprojectVMT<MPointer,Mem>,
|
|
mmergejoinprojectVMT<MPointer,MPointer>
|
|
};
|
|
|
|
OperatorSpec mmergejoinprojectSpec(
|
|
" MREL x MREL x IDENT x IDENT x INDENT^+ -> mpointer ",
|
|
" rel1 rel2 mmergejoinproject[attr1, attr2, prjlist] ",
|
|
" joins the relations rel1 and rel2 on attributes attr1 and attr2,"
|
|
" respectively."
|
|
"It's assumed rel1 and rel2 are sorted by the join attributes. "
|
|
"The concatenated tuples are projected to the prjlist. ",
|
|
"query mten mplz mmergerjoinproject[No, PLZ; "
|
|
"No,PLZ,Ort] count"
|
|
);
|
|
|
|
int mmergejoinprojectSelect(ListExpr args){
|
|
int n1 = Mem::checkType(nl->First(args))?0:2;
|
|
int n2 = Mem::checkType(nl->Second(args))?0:1;
|
|
return n1+n2;
|
|
}
|
|
|
|
Operator mmergejoinprojectOp(
|
|
"mmergejoinproject",
|
|
mmergejoinprojectSpec.getStr(),
|
|
4,
|
|
mmergejoinprojectVM,
|
|
mmergejoinprojectSelect,
|
|
mmergejoinprojectTM
|
|
);
|
|
|
|
/*
|
|
9 N-tree support
|
|
|
|
6.1 ~mcreatentree~: Creation of an N-tree
|
|
|
|
6.1.1 Type Mapping
|
|
|
|
Applied for operators ~mcreatentree~ and ~mcreatentree2~
|
|
|
|
*/
|
|
template<bool useNTree2>
|
|
ListExpr mcreatentreeTM(ListExpr args) {
|
|
string err = (!useNTree2 ? "expected: MREL x attrname x int x int [x geoid]" :
|
|
"expected: MREL x attrname x int x int x int [x geoid]");
|
|
if (useNTree2) {
|
|
if (!nl->HasLength(args, 5) && !nl->HasLength(args, 6)) {
|
|
return listutils::typeError(" (5 or 6 arguments are required");
|
|
}
|
|
}
|
|
else {
|
|
if (!nl->HasLength(args, 4) && !nl->HasLength(args, 5)) {
|
|
return listutils::typeError(" (4 or 5 arguments are required");
|
|
}
|
|
}
|
|
if (!MPointer::checkType(nl->First(args))) {
|
|
return listutils::typeError(err + " (first arg is not an mpointer)");
|
|
}
|
|
if (nl->AtomType(nl->Second(args)) != SymbolType) {
|
|
return listutils::typeError(err + " (second argument is not a valid "
|
|
"attribute name)");
|
|
}
|
|
if (!CcInt::checkType(nl->Fourth(args))) {
|
|
return listutils::typeError(err + " (fourth argument is not an integer)");
|
|
}
|
|
bool geoidPresent = false;
|
|
if (!CcInt::checkType(nl->Third(args))) {
|
|
return listutils::typeError(err + " (third argument is not an integer)");
|
|
}
|
|
if (useNTree2) {
|
|
if (!CcInt::checkType(nl->Fifth(args))) {
|
|
return listutils::typeError(err + " (fifth argument is not an integer)");
|
|
}
|
|
if (nl->HasLength(args, 6)) {
|
|
if (!Geoid::checkType(nl->Sixth(args))) {
|
|
return listutils::typeError("sixth argument is not a geoid");
|
|
}
|
|
geoidPresent = true;
|
|
}
|
|
}
|
|
else {
|
|
if (nl->HasLength(args, 5)) {
|
|
if (!Geoid::checkType(nl->Fifth(args))) {
|
|
return listutils::typeError("fifth argument is not a geoid");
|
|
}
|
|
geoidPresent = true;
|
|
}
|
|
}
|
|
// extract tuple type from first argument
|
|
ListExpr tupletype;
|
|
ListExpr mpt = nl->Second(nl->Second(nl->First(args)));
|
|
if (!Relation::checkType(mpt)) {
|
|
return listutils::typeError(" mpointer to a non-relation");
|
|
}
|
|
tupletype = nl->Second(mpt);
|
|
ListExpr attrList = nl->Second(tupletype);
|
|
string name = nl->SymbolValue(nl->Second(args));
|
|
ListExpr type;
|
|
int index1 = listutils::findAttribute(attrList, name, type);
|
|
if (!index1) {
|
|
return listutils::typeError("attribute " + name + " not part of the tuple");
|
|
}
|
|
// support geoid only for point, mpoint, cupoint, cmpoint
|
|
if (geoidPresent) {
|
|
if (!Point::checkType(type) && !temporalalgebra::MPoint::checkType(type) &&
|
|
!temporalalgebra::CUPoint::checkType(type) &&
|
|
!temporalalgebra::CMPoint::checkType(type)) {
|
|
return listutils::typeError("geoid support only for (m|cu|cm|eps)point");
|
|
}
|
|
}
|
|
// check for supported type, extend if required
|
|
int no = mtreehelper::getTypeNo(type, 12);
|
|
if (no < 0) {
|
|
return listutils::typeError("no distance function available for type "
|
|
+ nl->ToString(type));
|
|
}
|
|
ListExpr resType;
|
|
if (useNTree2) {
|
|
resType = MPointer::wrapType(Mem::wrapType(nl->TwoElemList(
|
|
listutils::basicSymbol<MemoryNtree2Object<Point,StdDistComp<Point> > >(),
|
|
type)));
|
|
}
|
|
else {
|
|
resType = MPointer::wrapType(Mem::wrapType(nl->TwoElemList(
|
|
listutils::basicSymbol<MemoryNtreeObject<Point,StdDistComp<Point> > >(),
|
|
type)));
|
|
}
|
|
ListExpr appendList;
|
|
if (geoidPresent) {
|
|
appendList = nl->TwoElemList(nl->IntAtom(index1 - 1),
|
|
nl->StringAtom(nl->ToString(type)));
|
|
}
|
|
else {
|
|
appendList = nl->ThreeElemList(
|
|
nl->TwoElemList(listutils::basicSymbol<Geoid>(),
|
|
listutils::getUndefined()),
|
|
nl->IntAtom(index1 - 1),
|
|
nl->StringAtom(nl->ToString(type)));
|
|
}
|
|
ListExpr result = nl->ThreeElemList(nl->SymbolAtom(Symbols::APPEND()),
|
|
appendList, resType);
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
6.2 Value Mapping template
|
|
|
|
*/
|
|
template<class T>
|
|
int mcreatentreeVMT(Word* args, Word& result, int message, Word& local,
|
|
Supplier s) {
|
|
result = qp->ResultStorage(s);
|
|
MPointer* res = (MPointer*)result.addr;
|
|
MPointer* mrelp = (MPointer*)args[0].addr;
|
|
if (mrelp->isNull()) {
|
|
res->setPointer(0);
|
|
return 0;
|
|
}
|
|
Geoid* geoid = (Geoid*)args[4].addr;
|
|
int index = ((CcInt*)args[5].addr)->GetValue();
|
|
// string tn = ((CcString*) args[4].addr)->GetValue();
|
|
if (!geoid->IsDefined()) {
|
|
geoid = 0;
|
|
}
|
|
MemoryRelObject* mrel = (MemoryRelObject*) mrelp->GetValue();
|
|
int degree = ((CcInt*)args[2].addr)->GetValue();
|
|
int maxLeafSize = ((CcInt*)args[3].addr)->GetValue();
|
|
if (degree < 1 || maxLeafSize < 1 || degree > maxLeafSize) {
|
|
cout << "invalid parameters: degree=" << degree << ", maxLeafSize="
|
|
<< maxLeafSize << endl;
|
|
res->setPointer(0);
|
|
return 0;
|
|
}
|
|
int partitionStrategy = 0; // TODO: add parameter
|
|
vector<Tuple*>* v = mrel->getmmrel();
|
|
vector<MTreeEntry<T> > contents;
|
|
bool flobused = false;
|
|
T* attr = 0;
|
|
for (size_t i = 0; i < v->size(); i++) {
|
|
attr = (T*)(v->at(i)->GetAttribute(index));
|
|
MTreeEntry<T> entry(*attr, i + 1);
|
|
contents.push_back(entry);
|
|
flobused = flobused || (attr->NumOfFLOBs() > 0);
|
|
}
|
|
StdDistComp<T> dc(geoid);
|
|
NTree<MTreeEntry<T>, StdDistComp<T> >* tree =
|
|
new NTree<MTreeEntry<T>, StdDistComp<T> >(degree, maxLeafSize, dc);
|
|
tree->build(contents, partitionStrategy);
|
|
// cout << "entries: " << tree->getNoEntries() << ", nodes: "
|
|
// << tree->getNoNodes() << ", leaves: " << tree->getNoLeaves() << endl;
|
|
size_t usedMem = tree->memSize();
|
|
ListExpr typeList = nl->Second(qp->GetType(s));
|
|
MemoryNtreeObject<T, StdDistComp<T> >* ntree =
|
|
new MemoryNtreeObject<T, StdDistComp<T> >(tree, usedMem,
|
|
nl->ToString(typeList), !flobused, getDBname());
|
|
mtreehelper::increaseCounter("counterMCreateMTree",
|
|
ntree->getntree()->getDistComp().getNoDistFunCalls());
|
|
res->setPointer(ntree);
|
|
ntree->deleteIfAllowed();
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
6.3 Selection Function and Value Mapping Array
|
|
|
|
*/
|
|
int mcreatentreeSelect(ListExpr args) {
|
|
string attrName = nl->SymbolValue(nl->Second(args));
|
|
ListExpr attrList = nl->Second(nl->Second(nl->Second(nl->Second(nl->First(
|
|
args)))));
|
|
// mpointer mem rel tuple
|
|
ListExpr type;
|
|
listutils::findAttribute(attrList, attrName, type);
|
|
return mtreehelper::getTypeNo(type, 12);
|
|
}
|
|
|
|
// note: if adding attributes with flobs, the value mapping must be changed
|
|
|
|
ValueMapping mcreatentreeVM[] = {
|
|
mcreatentreeVMT<mtreehelper::t1>,
|
|
mcreatentreeVMT<mtreehelper::t2>,
|
|
mcreatentreeVMT<mtreehelper::t3>,
|
|
mcreatentreeVMT<mtreehelper::t4>,
|
|
mcreatentreeVMT<mtreehelper::t5>,
|
|
mcreatentreeVMT<mtreehelper::t6>,
|
|
mcreatentreeVMT<mtreehelper::t7>,
|
|
mcreatentreeVMT<mtreehelper::t8>,
|
|
mcreatentreeVMT<mtreehelper::t9>,
|
|
mcreatentreeVMT<mtreehelper::t10>,
|
|
mcreatentreeVMT<mtreehelper::t11>,
|
|
mcreatentreeVMT<mtreehelper::t12>
|
|
};
|
|
|
|
OperatorSpec mcreatentreeSpec(
|
|
"MREL(tuple) x attrname x int x int [x geoid] -> , mpointer(mem(mtree X))\n",
|
|
"mrel mcreatemtree[indexAttr, degree, maxLeafSize, [, geoid] ]\n",
|
|
"This operator creates an N-tree in main memory. "
|
|
"The first argument is a main memory relation containing the "
|
|
"tuples to be indexed. The second argument refers to the attribute "
|
|
"over that the index is built. The next two arguments represent the degree of"
|
|
" the tree and and maximum number of entries in a leaf.\n"
|
|
"The last argument is optional. It must be of type geoid and "
|
|
"can only be used if the index-attribute is of type point, mpoint, cupoint, "
|
|
"or cmpoint. If this argument is present, the distance between two objects "
|
|
"is computed as geographic distance on this geoid instead of using the "
|
|
"Euclidean distance.\n In detail, the following types are supported:\n\n"
|
|
" * point: p1->Distance(*p2, geoid)\n"
|
|
" * string: stringutils::ld->(s1->GetValue(), s2->GetValue())\n"
|
|
" * int: abs(i1->GetValue() - i2->GetValue())\n"
|
|
" * real: abs(r1->GetValue() - r2->GetValue())\n"
|
|
" * rect<d>: r1->Distance(*r2)\n"
|
|
" * mpoint: mp1->DistanceAvg(*mp2, geoid)\n"
|
|
" * cupoint: cup1->DistanceAvg(*cup2, true, geoid)\n"
|
|
" * cmpoint: cmp1->DistanceAvg(*cmp2, true, geoid)\n",
|
|
"let kinosM_ntree_GeoData = kinosM mcreatentree[GeoData, 5, 8]"
|
|
);
|
|
|
|
Operator mcreatentreeOp(
|
|
"mcreatentree",
|
|
mcreatentreeSpec.getStr(),
|
|
12,
|
|
mcreatentreeVM,
|
|
mcreatentreeSelect,
|
|
mcreatentreeTM<false>
|
|
);
|
|
|
|
/*
|
|
6.2 Value Mapping template
|
|
|
|
*/
|
|
template<class T>
|
|
int mcreatentree2VMT(Word* args, Word& result, int message, Word& local,
|
|
Supplier s) {
|
|
result = qp->ResultStorage(s);
|
|
MPointer* res = (MPointer*)result.addr;
|
|
MPointer* mrelp = (MPointer*)args[0].addr;
|
|
if (mrelp->isNull()) {
|
|
res->setPointer(0);
|
|
return 0;
|
|
}
|
|
Geoid* geoid = (Geoid*)args[5].addr;
|
|
int index = ((CcInt*)args[6].addr)->GetValue();
|
|
// string tn = ((CcString*) args[4].addr)->GetValue();
|
|
if (!geoid->IsDefined()) {
|
|
geoid = 0;
|
|
}
|
|
MemoryRelObject* mrel = (MemoryRelObject*) mrelp->GetValue();
|
|
CcInt *ccDegree = ((CcInt*)args[2].addr);
|
|
CcInt *ccMaxLeafSize = ((CcInt*)args[3].addr);
|
|
CcInt *ccRefPtsMethod = ((CcInt*)args[4].addr);
|
|
if (!ccDegree->IsDefined() || !ccMaxLeafSize->IsDefined() ||
|
|
!ccRefPtsMethod->IsDefined()) {
|
|
cout << "undefined input parameter" << endl;
|
|
res->setPointer(0);
|
|
return 0;
|
|
}
|
|
int degree = ccDegree->GetValue();
|
|
int maxLeafSize = ccMaxLeafSize->GetValue();
|
|
int refPtsMethod = ccRefPtsMethod->GetValue();
|
|
if (degree < 1 || maxLeafSize < 1 || degree > maxLeafSize) {
|
|
cout << "invalid parameters: degree=" << degree << ", maxLeafSize="
|
|
<< maxLeafSize << endl;
|
|
res->setPointer(0);
|
|
return 0;
|
|
}
|
|
if (refPtsMethod < 0 || refPtsMethod > 2) {
|
|
cout << "invalid parameter: refPtsMethod must be in {0, 1, 2}" << endl;
|
|
res->setPointer(0);
|
|
return 0;
|
|
}
|
|
int partitionStrategy = 0; // TODO: add parameter
|
|
vector<Tuple*>* v = mrel->getmmrel();
|
|
vector<MTreeEntry<T> > contents;
|
|
bool flobused = false;
|
|
T* attr = 0;
|
|
for (size_t i = 0; i < v->size(); i++) {
|
|
attr = (T*)(v->at(i)->GetAttribute(index));
|
|
MTreeEntry<T> entry(*attr, i + 1);
|
|
contents.push_back(entry);
|
|
flobused = flobused || (attr->NumOfFLOBs() > 0);
|
|
}
|
|
StdDistComp<T> dc(geoid);
|
|
NTree2<MTreeEntry<T>, StdDistComp<T> >* tree =
|
|
new NTree2<MTreeEntry<T>, StdDistComp<T> >(degree, maxLeafSize,
|
|
refPtsMethod, dc);
|
|
tree->build(contents, partitionStrategy);
|
|
// cout << "entries: " << tree->getNoEntries() << ", nodes: "
|
|
// << tree->getNoNodes() << ", leaves: " << tree->getNoLeaves() << endl;
|
|
size_t usedMem = tree->memSize();
|
|
ListExpr typeList = nl->Second(qp->GetType(s));
|
|
MemoryNtree2Object<T, StdDistComp<T> >* ntree2 =
|
|
new MemoryNtree2Object<T, StdDistComp<T> >(tree, usedMem,
|
|
nl->ToString(typeList), !flobused, getDBname());
|
|
mtreehelper::increaseCounter("counterMCreateMTree2",
|
|
ntree2->getntree2()->getDistComp().getNoDistFunCalls());
|
|
res->setPointer(ntree2);
|
|
ntree2->deleteIfAllowed();
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
6.3 Selection Function and Value Mapping Array
|
|
|
|
*/
|
|
int mcreatentree2Select(ListExpr args) {
|
|
string attrName = nl->SymbolValue(nl->Second(args));
|
|
ListExpr attrList = nl->Second(nl->Second(nl->Second(nl->Second(nl->First(
|
|
args)))));
|
|
// mpointer mem rel tuple
|
|
ListExpr type;
|
|
listutils::findAttribute(attrList, attrName, type);
|
|
return mtreehelper::getTypeNo(type, 12);
|
|
}
|
|
|
|
// note: if adding attributes with flobs, the value mapping must be changed
|
|
|
|
ValueMapping mcreatentree2VM[] = {
|
|
mcreatentree2VMT<mtreehelper::t1>,
|
|
mcreatentree2VMT<mtreehelper::t2>,
|
|
mcreatentree2VMT<mtreehelper::t3>,
|
|
mcreatentree2VMT<mtreehelper::t4>,
|
|
mcreatentree2VMT<mtreehelper::t5>,
|
|
mcreatentree2VMT<mtreehelper::t6>,
|
|
mcreatentree2VMT<mtreehelper::t7>,
|
|
mcreatentree2VMT<mtreehelper::t8>,
|
|
mcreatentree2VMT<mtreehelper::t9>,
|
|
mcreatentree2VMT<mtreehelper::t10>,
|
|
mcreatentree2VMT<mtreehelper::t11>,
|
|
mcreatentree2VMT<mtreehelper::t12>
|
|
};
|
|
|
|
OperatorSpec mcreatentree2Spec(
|
|
"MREL(tuple) x attrname x int x int x int [x geoid] -> mpointer(mem(mtree X))"
|
|
"\n",
|
|
"mrel mcreatemtree[indexAttr, degree, maxLeafSize, refPtsMethod [, geoid]]\n",
|
|
"This operator creates an N-tree2 in main memory. "
|
|
"The first argument is a main memory relation containing the "
|
|
"tuples to be indexed. The second argument refers to the attribute "
|
|
"over that the index is built. The next two arguments represent the degree of"
|
|
" the tree and and maximum number of entries in a leaf.\n"
|
|
"The fifth argument represents the selection method for r1 and r2: (0 <=> "
|
|
"maxDist, 1 <=> random, 2 <=> median dist)\n"
|
|
"The last argument is optional. It must be of type geoid and "
|
|
"can only be used if the index-attribute is of type point, mpoint, cupoint, "
|
|
"or cmpoint. If this argument is present, the distance between two objects "
|
|
"is computed as geographic distance on this geoid instead of using the "
|
|
"Euclidean distance.\n In detail, the following types are supported:\n\n"
|
|
" * point: p1->Distance(*p2, geoid)\n"
|
|
" * string: stringutils::ld->(s1->GetValue(), s2->GetValue())\n"
|
|
" * int: abs(i1->GetValue() - i2->GetValue())\n"
|
|
" * real: abs(r1->GetValue() - r2->GetValue())\n"
|
|
" * rect<d>: r1->Distance(*r2)\n"
|
|
" * mpoint: mp1->DistanceAvg(*mp2, geoid)\n"
|
|
" * cupoint: cup1->DistanceAvg(*cup2, true, geoid)\n"
|
|
" * cmpoint: cmp1->DistanceAvg(*cmp2, true, geoid)\n",
|
|
"let kinosM_ntree_GeoData = kinosM mcreatentree[GeoData, 5, 8]"
|
|
);
|
|
|
|
Operator mcreatentree2Op(
|
|
"mcreatentree2",
|
|
mcreatentree2Spec.getStr(),
|
|
12,
|
|
mcreatentree2VM,
|
|
mcreatentree2Select,
|
|
mcreatentreeTM<true>
|
|
);
|
|
|
|
/*
|
|
23 Algebra Definition
|
|
|
|
*/
|
|
|
|
|
|
class MainMemory2Algebra : public Algebra {
|
|
|
|
public:
|
|
MainMemory2Algebra() : Algebra() {
|
|
if(!catalog){
|
|
catalog = MemCatalog::getInstance();
|
|
}
|
|
|
|
/*
|
|
|
|
8.2 Registration of Types
|
|
|
|
|
|
*/
|
|
AddTypeConstructor (&MPointerTC);
|
|
MPointerTC.AssociateKind( Kind::SIMPLE() );
|
|
|
|
AddTypeConstructor (&MemTC);
|
|
MemTC.AssociateKind( Kind::DATA() );
|
|
|
|
/*
|
|
8.3 Registration of Operators
|
|
|
|
*/
|
|
AddOperator (&memloadOp);
|
|
AddOperator (&memloadflobOp);
|
|
|
|
AddOperator (&meminitOp);
|
|
meminitOp.SetUsesMemory();
|
|
|
|
AddOperator (&mfeedOp);
|
|
|
|
AddOperator (&memobjectOp);
|
|
|
|
AddOperator (&memgetcatalogOp);
|
|
|
|
AddOperator (&mcreatertreeOp);
|
|
|
|
AddOperator (&memsizeOp);
|
|
AddOperator (&memclearOp);
|
|
|
|
AddOperator (&meminsertOp);
|
|
|
|
AddOperator (&mwindowintersectsOp);
|
|
|
|
|
|
AddOperator (&mwindowintersectsSOp);
|
|
|
|
AddOperator (&mconsumeOp);
|
|
AddOperator (&mconsumeflobOp);
|
|
|
|
|
|
AddOperator (&mcreateAVLtreeOp);
|
|
|
|
AddOperator (&mexactmatchOp);
|
|
mexactmatchOp.enableInitFinishSupport();
|
|
|
|
AddOperator (&mrangeOp);
|
|
|
|
AddOperator (&matchbelowOp);
|
|
|
|
AddOperator (&matchbelow2Op);
|
|
|
|
AddOperator(&mcreatemtreeOp);
|
|
AddOperator(&mcreatemtree2Op);
|
|
AddOperator(&minsertmtreeOp);
|
|
AddOperator(&mdistRange2Op);
|
|
|
|
AddOperator(&mdistScan2Op);
|
|
|
|
AddOperator(&mdistRangeOp);
|
|
AddOperator(&mdistRangeNOp);
|
|
|
|
AddOperator(&mdistScanOp);
|
|
|
|
AddOperator(&mexactmatchSOp);
|
|
|
|
AddOperator(&mrangeSOp);
|
|
|
|
AddOperator(&matchbelowSOp);
|
|
|
|
AddOperator(&gettuplesOp);
|
|
|
|
AddOperator(&mcreatentreeOp);
|
|
|
|
AddOperator(&mcreatentree2Op);
|
|
|
|
////////////////////// MainMemory2Algebra////////////////////////////
|
|
|
|
AddOperator(&mwrapOp);
|
|
mwrapOp.SetUsesArgsInTypeMapping();
|
|
AddOperator(&mwrap2Op);
|
|
mwrap2Op.SetUsesArgsInTypeMapping();
|
|
AddOperator(&mwrap3Op);
|
|
|
|
|
|
AddOperator(&MTUPLEOp);
|
|
AddOperator(&MTUPLE2Op);
|
|
|
|
AddOperator(&mcreatettreeOp);
|
|
|
|
AddOperator(&minsertttreeOp);
|
|
|
|
AddOperator(&mdeletettreeOp);
|
|
AddOperator(&minsertavltreeOp);
|
|
AddOperator(&mdeleteavltreeOp);
|
|
|
|
AddOperator(&mcreateinsertrelOp);
|
|
AddOperator(&minsertOp);
|
|
minsertOp.enableInitFinishSupport();
|
|
AddOperator(&minsertsaveOp);
|
|
AddOperator(&minserttupleOp);
|
|
AddOperator(&minserttuplesaveOp);
|
|
|
|
AddOperator(&mcreatedeleterelOp);
|
|
AddOperator(&mdeleteOp);
|
|
|
|
AddOperator(&mdeletesaveOp);
|
|
AddOperator(&mdeletebyidOp);
|
|
AddOperator(&mdeletedirectOp);
|
|
AddOperator(&mdeletedirectsaveOp);
|
|
|
|
AddOperator(&mcreateupdaterelOp);
|
|
AddOperator(&mupdateNOp);
|
|
AddOperator(&mupdatesaveOp);
|
|
|
|
AddOperator(&mupdatebyidOp);
|
|
mupdatebyidOp.enableInitFinishSupport();
|
|
|
|
AddOperator(&mupdatedirect2Op);
|
|
|
|
AddOperator(&moinsertOp);
|
|
AddOperator(&modeleteOp);
|
|
AddOperator(&moconsumeOp);
|
|
AddOperator(&moconsumeflobOp);
|
|
AddOperator(&morangeOp);
|
|
AddOperator(&moleftrangeOp);
|
|
AddOperator(&morightrangeOp);
|
|
|
|
AddOperator(&moshortestpathdOp);
|
|
AddOperator(&moshortestpathaOp);
|
|
|
|
AddOperator(&moconnectedcomponentsOp);
|
|
|
|
AddOperator(&mquicksortOp);
|
|
AddOperator(&mquicksortbyOp);
|
|
|
|
AddOperator (&mcreatemgraphOp);
|
|
AddOperator (&mcreatemgraphflobOp);
|
|
|
|
AddOperator(&mgshortestpathdOp);
|
|
AddOperator(&mgshortestpathaOp);
|
|
AddOperator(&mgconnectedcomponentsOp);
|
|
AddOperator(&mgconnectedcomponentsNOp);
|
|
AddOperator(&mgconnectedcomponents_oldOp);
|
|
|
|
AddOperator(&pwrapOp);
|
|
pwrapOp.SetUsesArgsInTypeMapping();
|
|
|
|
|
|
// operations on mvector
|
|
AddOperator(&collect_mvectorOp);
|
|
AddOperator(&sizemvOp);
|
|
AddOperator(&getmvOp);
|
|
AddOperator(&putmvOp);
|
|
AddOperator(&isSortedmvOp);
|
|
AddOperator(&sortmvOp);
|
|
AddOperator(&feedmvOp);
|
|
AddOperator(&findmvOp);
|
|
AddOperator(&matchbelowmvOp);
|
|
AddOperator(&insertmvOp);
|
|
AddOperator(&countOp);
|
|
|
|
// operators on priority queues
|
|
AddOperator(&mcreatepqueueOp);
|
|
AddOperator(&mcreatepqueueflobOp);
|
|
|
|
AddOperator(&sizeOp);
|
|
AddOperator(&mfeedpqOp);
|
|
AddOperator(&mfeedpqSizeOp);
|
|
AddOperator(&mfeedpqAbortOp);
|
|
|
|
AddOperator(&minsertTuplepqOp);
|
|
AddOperator(&minserttuplepqprojectOp);
|
|
AddOperator(&minserttuplepqprojectUOp);
|
|
|
|
AddOperator(&mpqreorderOp);
|
|
AddOperator(&mpqreorderupdateOp);
|
|
|
|
// operators on stack
|
|
AddOperator(&mfeedstackOp);
|
|
|
|
AddOperator(&mcreatestackOp);
|
|
AddOperator(&mcreatestackflobOp);
|
|
AddOperator(&stacksizeOp);
|
|
AddOperator(&insertmstackOp);
|
|
|
|
AddOperator(&mblockOp);
|
|
|
|
// operators on mgraph2
|
|
|
|
AddOperator(&createmgraph2Op);
|
|
AddOperator(&createmgraph2flobOp);
|
|
AddOperator(&mg2insertorigOp);
|
|
AddOperator(&mg2insertOp);
|
|
AddOperator(&mg2feedOp);
|
|
AddOperator(&mg2nodemapOp);
|
|
AddOperator(&mg2numverticesOp);
|
|
AddOperator(&mg2successorsOp);
|
|
AddOperator(&mg2predecessorsOp);
|
|
AddOperator(&mg2numsuccessorsOp);
|
|
AddOperator(&mg2numpredecessorsOp);
|
|
AddOperator(&mg2disconnectOp);
|
|
AddOperator(&mg2deleteEdgesOp);
|
|
AddOperator(&mg2contractOp);
|
|
AddOperator(&mg2minPathCostOp);
|
|
AddOperator(&mg2exportddsgOp);
|
|
AddOperator(&mg2connectedcomponentsOp);
|
|
mg2connectedcomponentsOp.enableInitFinishSupport();
|
|
AddOperator(&mg2connectedcomponentsNOp);
|
|
mg2connectedcomponentsNOp.enableInitFinishSupport();
|
|
|
|
// operators on mgraph3
|
|
AddOperator(&createmgraph3Op);
|
|
AddOperator(&createmgraph3flobOp);
|
|
|
|
AddOperator(&mg3insertOp);
|
|
AddOperator(&mg3feedOp);
|
|
AddOperator(&mg3numverticesOp);
|
|
AddOperator(&mg3successorsOp);
|
|
AddOperator(&mg3predecessorsOp);
|
|
AddOperator(&mg3numsuccessorsOp);
|
|
AddOperator(&mg3numpredecessorsOp);
|
|
AddOperator(&mg3disconnectOp);
|
|
AddOperator(&mg3deleteEdgesOp);
|
|
AddOperator(&mg3connectedcomponentsOp);
|
|
mg3connectedcomponentsOp.enableInitFinishSupport();
|
|
AddOperator(&mg3connectedcomponentsNOp);
|
|
mg3connectedcomponentsNOp.enableInitFinishSupport();
|
|
|
|
AddOperator(&mg3contractOp);
|
|
AddOperator(&mg3minPathCostOp);
|
|
AddOperator(&mg3exportddsgOp);
|
|
|
|
AddOperator(&mgraphPrintOp);
|
|
AddOperator(&mgraph2textOp);
|
|
|
|
AddOperator(&mgroupOp);
|
|
AddOperator(&memgroupbyOp);
|
|
memgroupbyOp.enableInitFinishSupport();
|
|
|
|
AddOperator(&importCHOp),
|
|
importCHOp.SetUsesArgsInTypeMapping();
|
|
|
|
AddOperator(&mmergejoinprojectOp);
|
|
|
|
}
|
|
|
|
~MainMemory2Algebra() {
|
|
MemCatalog::destroyInstance();
|
|
};
|
|
};
|
|
|
|
} // end of namespace mmalgebra
|
|
|
|
/*
|
|
9 Initialization
|
|
|
|
Each algebra module needs an initialization function. The algebra manager
|
|
has a reference to this function if this algebra is included in the list
|
|
of required algebras, thus forcing the linker to include this module.
|
|
|
|
The algebra manager invokes this function to get a reference to the instance
|
|
of the algebra class and to provide references to the global nested list
|
|
container (used to store constructor, type, operator and object information)
|
|
and to the query processor.
|
|
|
|
The function has a C interface to make it possible to load the algebra
|
|
dynamically at runtime (if it is built as a dynamic link library). The name
|
|
of the initialization function defines the name of the algebra module. By
|
|
convention it must start with "Initialize<AlgebraName>".
|
|
|
|
To link the algebra together with the system you must create an
|
|
entry in the file "makefile.algebra" and to define an algebra ID in the
|
|
file "Algebras/Management/AlgebraList.i.cfg".
|
|
|
|
*/
|
|
|
|
extern "C"
|
|
Algebra*
|
|
InitializeMainMemory2Algebra(NestedList* nlRef, QueryProcessor* qpRef)
|
|
{
|
|
return (new mm2algebra::MainMemory2Algebra);
|
|
}
|
|
|