/* ---- This file is part of SECONDO. Copyright (C) 2004-2008, 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 ---- //paragraph [1] Title: [{\Large \bf \begin{center}] [\end{center}}] //paragraph [10] Footnote: [{\footnote{] [}}] //[TOC] [\tableofcontents] [1] Implementation of Module Update Relation Algebra June 2005 Matthias Zielke January 2006, Victor Almeida separated this algebra from the Extended Relational Algebra and fixed some memory leaks. October 2007, M. Spiekermann fixed bugs in the implementations of the operators ~updatedirectsave~ and ~updatedirectsearch~. June 2008, M. Spiekermann bug fix for operator ~updatesearchsave~. However, the implementation is still limited since the code expects that the relation to be searched on can be hold in an random memory based hash table. [TOC] 1 Includes and defines */ #include #include "Algebras/Relation-C++/RelationAlgebra.h" #include "QueryProcessor.h" #include "StandardTypes.h" #include "Counter.h" #include "Algebras/TupleIdentifier/TupleIdentifier.h" #include "LogMsg.h" #include "Algebras/RTree/RTreeAlgebra.h" #include "ListUtils.h" #include "Symbols.h" #include "Stream.h" #include #include "Algebras/OrderedRelation/OrderedRelationAlgebra.h" extern NestedList* nl; extern QueryProcessor* qp; using namespace std; /* 2 Operators 2.19 Operators ~createinsertrel~, ~createdeleterel~ and ~createupdaterel~ Create an empty relation with the schema of the result-tupletyp of the corresponding 'update'-operators. This operator is used to create an auxiliary relation for updates on relations which shall be passed to existing indices later on. 2.19.1 General Type mapping function of operators ~createinsertrel~, ~createdeleterel~ and ~createupdaterel~ Type mapping ~createinsertrel~, ~createdeleterel~, and ~createupdaterel~ ---- (rel X) -> (rel(tuple((a1 x1) ... (an xn) (TID tid)))) where X = (tuple ((a1 x1) ... (an xn))) ---- Type mapping ~createupdaterel~ ---- (rel X) -> (rel(tuple(X (a1_old x1) ... (an_old xn) (TID tid)))) where X = (tuple ((a1 x1) ... (an xn))) ---- */ ListExpr createAuxiliaryRelTypeMap( const ListExpr& args, const string opName ) { ListExpr first,rest,listn,lastlistn,oldAttribute, outList; string oldName; string argstr; if(nl->ListLength(args)!=1){ return listutils::typeError("one argument expected"); } first = nl->First(args); if(!listutils::isRelDescription(first) && !listutils::isOrelDescription(first)){ return listutils::typeError("relation expected"); } // build first part of the result-tupletype rest = nl->Second(nl->Second(first)); listn = nl->OneElemList(nl->First(rest)); lastlistn = listn; rest = nl->Rest(rest); while (!(nl->IsEmpty(rest))) { lastlistn = nl->Append(lastlistn,nl->First(rest)); rest = nl->Rest(rest); } if ( opName == "createupdaterel") // 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)); 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()))); outList = nl->TwoElemList( nl->SymbolAtom(Relation::BasicType()), nl->TwoElemList( nl->SymbolAtom(Tuple::BasicType()), listn)); return outList; } ListExpr createInsertRelTypeMap( ListExpr args) { return createAuxiliaryRelTypeMap( args, "createinsertrel"); } ListExpr createDeleteRelTypeMap( ListExpr args) { return createAuxiliaryRelTypeMap( args, "createdeleterel"); } ListExpr createUpdateRelTypeMap( ListExpr args) { return createAuxiliaryRelTypeMap( args, "createupdaterel"); } /* 2.19.2 General Value mapping function of operators ~createinsertrel~, ~createdeleterel~ and ~createupdaterel~ */ int createUpdateRelValueMap(Word* args, Word& result, int message, Word& local, Supplier s) { result = qp->ResultStorage( s ); return 0; } /* 2.19.3 Specification of operator ~createinsertrel~ */ const string createinsertrelSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" " "\"Example\" ) " "( rel(tuple(x))" " -> rel(tuple(x@[TID:tid]))] " "" "_ createinsertrel" "Creates an empty relation with the schema of the " "result-tupletype of the 'insert'-operators. " "let staedteI = staedte createinsertrel " "" ") )"; /* 2.19.4 Definition of operator ~createinsertrel~ */ Operator extrelcreateinsertrel ( "createinsertrel", // name createinsertrelSpec, // specification createUpdateRelValueMap, // value mapping Operator::SimpleSelect, // trivial selection function createInsertRelTypeMap // type mapping ); /* 2.20.3 Specification of operator ~createdeleterel~ */ const string createdeleterelSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" " "\"Example\" ) " "( rel(tuple(x))" " -> rel(tuple(x@[TID:tid]))] " "" "_ createdeleterel" "Creates an empty relation with the schema of the " "result-tupletype of the 'delete'-operators. " "let staedteD = staedte createdeleterel" "" ") )"; /* 2.20.4 Definition of operator ~createdeleterel~ */ Operator extrelcreatedeleterel ( "createdeleterel", // name createdeleterelSpec, // specification createUpdateRelValueMap, // value mapping Operator::SimpleSelect, // trivial selection function createDeleteRelTypeMap // type mapping ); /* 2.21.3 Specification of operator ~createupdaterel~ */ const string createupdaterelSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" " "\"Example\" ) " "( rel(tuple(x))" " -> rel(tuple(x@[(a1_old x1)...(an_old xn)(TID:tid)]))] " "" "_ createupdaterel" "Creates an empty relation with the schema of the " "result-tupletype of the 'update'-operators. " "let staedteU = staedte createupdaterel " "" ") )"; /* 2.21.4 Definition of operator ~createupdaterel~ */ Operator extrelcreateupdaterel ( "createupdaterel", // name createupdaterelSpec, // specification createUpdateRelValueMap, // value mapping Operator::SimpleSelect, // trivial selection function createUpdateRelTypeMap // type mapping ); bool equalTuplesIgnore(ListExpr tuple1, ListExpr tuple2, bool wholeName){ ListExpr attrList1 = nl->Second(tuple1); ListExpr attrList2 = nl->Second(tuple2); while(!nl->IsEmpty(attrList1) && !nl->IsEmpty(attrList2)){ ListExpr attr1 = nl->First(attrList1); ListExpr attr2 = nl->First(attrList2); attrList1 = nl->Rest(attrList1); attrList2 = nl->Rest(attrList2); if(!nl->HasLength(attr1,2) || !nl->HasLength(attr2,2)){ return false; } if(!nl->Equal(nl->Second(attr1), nl->Second(attr2))){ return false; } if(!wholeName){ string a1 = nl->SymbolValue(nl->First(attr1)); string a2 = nl->SymbolValue(nl->First(attr2)); stringutils::toLower(a1); stringutils::toLower(a2); if( a1 != a2) { return false; } } } if(!nl->IsEmpty(attrList1) || !nl->IsEmpty(attrList2)){ return false; } return true; } /* 2.22 Operator ~insert~ Inserts each tuple of the inputstream into the 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. 2.22.0 General type mapping function of operators ~insert~, ~deletesearch~, and ~deletedirect~ General type mapping for operators ~insert~ ,~deletesearch~ and ~deletedirect~ ---- (stream X) (rel X) -> (stream (tuple ((a1 x1) ... (an xn) (TID tid)))) where X = (tuple ((a1 x1) ... (an xn))) ---- The equalcheck determines how the equality of the stream tuple type and the relation typle type is checked. * 0 : complete equality, * 1 : attribute names are checked case insensitiv, * 2 : only the types are equal, attribute names are not checked */ template ListExpr insertDeleteRelTypeMap( ListExpr args) { ListExpr first, second, rest,listn,lastlistn, outList; string argstr, argstr2; if(nl->ListLength(args)!=2){ return listutils::typeError("two arguments expected"); } first = nl->First(args); second = nl->Second(args); if(!listutils::isTupleStream(first)){ return listutils::typeError("first argument must be a tuple stream"); } if(!listutils::isRelDescription(second) && !listutils::isOrelDescription(second)){ return listutils::typeError("second argument must be of type rel or orel"); } ListExpr streamTuple = nl->Second(first); ListExpr relTuple = nl->Second(second); switch(equalCheck){ case 0 : if(!nl->Equal(streamTuple,relTuple)){ return listutils::typeError("tuple types in stream and " "relation differ"); } break; case 1: if(!equalTuplesIgnore(streamTuple, relTuple,false)){ return listutils::typeError("tuple types in stream and " "relation differ"); } break; case 2: if(!equalTuplesIgnore(streamTuple, relTuple,true)){ return listutils::typeError("tuple types in stream and " "relation differ"); } break; default : assert(false); } // build resultllist rest = nl->Second(nl->Second(second)); listn = nl->OneElemList(nl->First(rest)); 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()))); outList = nl->TwoElemList( nl->SymbolAtom(Symbol::STREAM()), nl->TwoElemList( nl->SymbolAtom(Tuple::BasicType()), listn)); return outList; } /* 2.22.2 Value mapping function of operator ~insert~ */ int insertRelValueMap(Word* args, Word& result, int message, Word& local, Supplier s) { Word t; Tuple* tup; GenericRelation* relation; TupleType *resultTupleType; ListExpr resultType; switch (message) { case OPEN : qp->Open(args[0].addr); resultType = GetTupleResultType( s ); resultTupleType = new TupleType( nl->Second( resultType ) ); local.setAddr( resultTupleType ); return 0; case REQUEST : resultTupleType = (TupleType*) local.addr; relation = (GenericRelation*)(args[1].addr); assert(relation != 0); qp->Request(args[0].addr,t); if (qp->Received(args[0].addr)) { tup = (Tuple*)t.addr; Tuple *newTuple = new Tuple( resultTupleType ); for( int i = 0; i < tup->GetNoAttributes(); i++ ) newTuple->CopyAttribute( i, tup, i ); relation->AppendTuple(tup); const TupleId& tid = tup->GetTupleId(); Attribute* tidAttr = new TupleIdentifier(true,tid); newTuple->PutAttribute( tup->GetNoAttributes(), tidAttr ); result.setAddr(newTuple); tup->DeleteIfAllowed(); qp->SetModified(qp->GetSon(s, 1)); return YIELD; } else return CANCEL; case CLOSE : qp->Close(args[0].addr); if(local.addr) { resultTupleType = (TupleType*) local.addr; resultTupleType->DeleteIfAllowed(); local.setAddr(0); } return 0; } return 0; } /* 2.22.3 Specification of operator ~insert~ */ const string insertSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" " "\"Example\" ) " "( stream(tuple(x)) x rel(tuple(x))" " -> stream(tuple(x@[TID:tid]))] " "" "_ _ insert" "Inserts all tuples of the stream " "into the relation." "query neueStaedte feed staedte insert " "consume" "" ") )"; /* 2.22.4 Definition of operator ~insert~ */ Operator extrelinsert ( "insert", // name insertSpec, // specification insertRelValueMap, // value mapping Operator::SimpleSelect, // trivial selection function insertDeleteRelTypeMap<0> // type mapping ); OperatorSpec insert2Spec( "stream(tuple(x)) x rel(tuple(x)) -> stream(tuple(x@[TID:tid]))", "_ _ insert2", "Inserts all tuples from the stream into a relation. " "The schema of the tuple stream has to fit the schema of " "the relation where attribute names are compared case insensitive.", "query towns feed vilages insert count" ); Operator extrelinsert2 ( "insert2", // name insert2Spec.getStr(), // specification insertRelValueMap, // value mapping Operator::SimpleSelect, // trivial selection function insertDeleteRelTypeMap<1> ); OperatorSpec insert3Spec( "stream(tuple(x)) x rel(tuple(x)) -> stream(tuple(x@[TID:tid]))", "_ _ insert2", "Inserts all tuples from the stream into a relation. " "The schema of the tuple stream has to fit the schema of " "the relation where attribute names are ignored.", "query towns feed vilages insert count" ); Operator extrelinsert3 ( "insert3", // name insert3Spec.getStr(), // specification insertRelValueMap, // value mapping Operator::SimpleSelect, // trivial selection function insertDeleteRelTypeMap<2> ); /* 2.23 Operator ~insertsave~ Inserts each tuple of the inputstream into the 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 thei tupleidentifier of the inserted tuple in the extended relation. In addition all the tuples of the resultstream are inserted into the auxiliary relation which is given as the third argument. 2.23.1 Type mapping function of operator ~insertsave~ Type mapping ~insertsave~ on a relation ---- (stream X) (rel X) (rel X@[(TID tid)]) -> (stream (tuple ((a1 x1) ... (an xn) (TID tid)))) where X = (tuple ((a1 x1) ... (an xn))) ---- */ ListExpr insertSaveRelTypeMap( ListExpr args ) { ListExpr first, second, third,rest,listn,lastlistn, outList; string argstr, argstr2; if(nl->ListLength(args)!=3){ return listutils::typeError("three arguments expected"); } first = nl->First(args); second = nl->Second(args); third = nl->Third(args); if(!listutils::isTupleStream(first)){ return listutils::typeError("first argument must be a tuple stream"); } if(!listutils::isRelDescription(second) && !listutils::isOrelDescription(second)){ return listutils::typeError("second argument must be a relation"); } if(!listutils::isRelDescription(third)){ return listutils::typeError("third argument must be a relation"); } if(!nl->Equal(nl->Second(first),nl->Second(second))){ return listutils::typeError("tuple types of the first and " "second argument have to be equal"); } // build resutllist rest = nl->Second(nl->Second(second)); listn = nl->OneElemList(nl->First(rest)); 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()))); if(!nl->Equal(listn, nl->Second(nl->Second(third)))){ return listutils::typeError("tuple type of the third argument must equal " "to the tuple type of the first arguments with an additional " "tid as last attribute"); } outList = nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()), nl->TwoElemList(nl->SymbolAtom(Tuple::BasicType()),listn)); return outList; } /* 2.23.2 Value mapping function of operator ~insertsave~ */ int insertSaveRelValueMap(Word* args, Word& result, int message, Word& local, Supplier s) { Word t; Tuple* tup; GenericRelation* relation; Relation* auxRelation; TupleType *resultTupleType; ListExpr resultType; switch (message) { case OPEN : qp->Open(args[0].addr); resultType = GetTupleResultType( s ); resultTupleType = new TupleType( nl->Second( resultType ) ); local.setAddr( resultTupleType ); return 0; case REQUEST : resultTupleType = (TupleType*) local.addr; relation = (Relation*)(args[1].addr); assert(relation != 0); auxRelation = (Relation*)(args[2].addr); assert(auxRelation != 0); qp->Request(args[0].addr,t); if (qp->Received(args[0].addr)) { tup = (Tuple*)t.addr; relation->AppendTuple(tup); Tuple *newTuple = new Tuple( resultTupleType ); for( int i = 0; i < tup->GetNoAttributes(); i++ ) newTuple->CopyAttribute( i, tup, i ); const TupleId& tid = tup->GetTupleId(); Attribute* tidAttr = new TupleIdentifier(true,tid); newTuple->PutAttribute( tup->GetNoAttributes(), tidAttr ); auxRelation->AppendTuple(newTuple); result.setAddr(newTuple); tup->DeleteIfAllowed(); qp->SetModified(qp->GetSon(s, 1)); qp->SetModified(qp->GetSon(s, 2)); return YIELD; } else return CANCEL; case CLOSE : qp->Close(args[0].addr); if(local.addr) { resultTupleType = (TupleType*) local.addr; resultTupleType->DeleteIfAllowed(); local.setAddr(0); } return 0; } return 0; } /* 2.23.3 Specification of operator ~insertsave~ */ const string insertSaveSpec = "(( \"Signature\" \"Syntax\" \"Meaning\" " "\"Example\" ) " "(stream(tuple(x)) x rel(tuple(x)) x rel(tuple(x@[TID:tid]))" " -> stream(tuple(x@[TID:tid]))] " "" "_ _ _insertsave" "Like insert but appends all result-tuples to " "an auxiliary relation." "query neueStaedte feed staedte staedteI insertsave " "consume" "" ") )"; /* 2.23.4 Definition of operator ~insertsave~ */ Operator extrelinsertsave ( "insertsave", // name insertSaveSpec, // specification insertSaveRelValueMap, // value mapping Operator::SimpleSelect, // trivial selection function insertSaveRelTypeMap // type mapping ); /* 2.24 Operator ~deletesearch~ Deletes each tuple from the relation which attribut-values are exactly the same as those ones of a tuple of the inputstream. Returns a stream of tuples which is basically the stream of deleted tuples but each tuple extended by an attribute of type 'tid' which is the tupleidentifier of the deleted tuple in the extended relation. */ /* 2.24.2 Value mapping function of operator ~deletesearch~ */ int deleteSearchRelValueMap(Word* args, Word& result, int message, Word& local, Supplier s) { Word t; Tuple* tup; Tuple* nextTup; Tuple* newTuple; GenericRelation* relation; GenericRelationIterator* iter; ListExpr resultType; vector* nextBucket; struct LocalTransport { LocalTransport(): deletedTuples( new vector() ), hashTable( new vector*>(256) ), resultTupleType( 0 ) { for (int i = 0; i < 256; i++) (*hashTable)[i] = new vector(); } ~LocalTransport() { for( vector::iterator i = deletedTuples->begin(); i != deletedTuples->end(); i++ ) { (*i)->DeleteIfAllowed(); } delete deletedTuples; for (int i = 0; i < 256; i++) { for( vector::iterator j = (*hashTable)[i]->begin(); j != (*hashTable)[i]->end(); j++ ) { (*j)->DeleteIfAllowed(); } delete (*hashTable)[i]; } delete hashTable; resultTupleType->DeleteIfAllowed(); } vector* deletedTuples; vector*>* hashTable; TupleType* resultTupleType; } *localTransport; size_t hashValue ; bool tupleFound; switch (message) { case OPEN : qp->Open(args[0].addr); localTransport = new LocalTransport(); relation = (GenericRelation*)(args[1].addr); assert(relation != 0); iter = relation->MakeScan(); nextTup = iter->GetNextTuple(); // fill hashtable while (!iter->EndOfScan()) { hashValue = 0; for( int i = 0; i < nextTup->GetNoAttributes(); i++ ) hashValue += ((Attribute*) (nextTup->GetAttribute(i)))->HashValue(); nextBucket = localTransport->hashTable->operator[](hashValue % 256); nextBucket->push_back(nextTup); nextTup = iter->GetNextTuple(); } delete iter; resultType = GetTupleResultType( s ); localTransport->resultTupleType = new TupleType( nl->Second( resultType ) ); local.setAddr( localTransport ); return 0; case REQUEST : localTransport = (LocalTransport*) local.addr; // deletedTuples can contain duplicates that have not been // given to the resultstream yet if (!localTransport->deletedTuples->empty()) { newTuple = localTransport->deletedTuples->back(); newTuple->DeleteIfAllowed(); localTransport->deletedTuples->pop_back(); result.setAddr(newTuple); return YIELD; } // no duplicate has to be send to the resultstream relation = (GenericRelation*)(args[1].addr); assert(relation != 0); tupleFound = false; // tupleFound will stay false until a matching tuple to a // inputtuple was found while (! tupleFound) { qp->Request(args[0].addr,t); if (qp->Received(args[0].addr)) { tup = (Tuple*)t.addr; hashValue = 0; for( int i = 0; i < tup->GetNoAttributes(); i++ ) hashValue += ((Attribute*) (tup->GetAttribute(i)))->HashValue(); SortOrderSpecification full; for( int i = 0; i < tup->GetNoAttributes(); i++ ) full.push_back(pair (i+1,false)); TupleCompareBy compare(full); // get correct bucket from hashtable nextBucket = localTransport->hashTable->operator[](hashValue % 256); // look for all matching tuples in the bucket for (size_t j = 0; j < nextBucket->size(); j++) { nextTup = nextBucket->operator[](j); if (nextTup != 0) { if(!compare(nextTup,tup) && !compare(tup,nextTup)) { newTuple = new Tuple(localTransport->resultTupleType); assert( newTuple->GetNoAttributes() == nextTup->GetNoAttributes() + 1 ); for( int i = 0; i < nextTup->GetNoAttributes(); i++ ) newTuple->PutAttribute( i, (nextTup->GetAttribute(i))->Clone() ); const TupleId& tid = nextTup->GetTupleId(); Attribute* tidAttr = new TupleIdentifier(true,tid); newTuple->PutAttribute( nextTup->GetNoAttributes(), tidAttr ); relation->DeleteTuple(nextTup); newTuple->IncReference(); localTransport->deletedTuples->push_back(newTuple); } } } if (!localTransport->deletedTuples->empty()) { newTuple = localTransport->deletedTuples->back(); newTuple->DeleteIfAllowed(); localTransport->deletedTuples->pop_back(); result.setAddr(newTuple); tupleFound = true; } tup->DeleteIfAllowed(); } else// if (qp->Received(args[0].addr)) return CANCEL; }// while (! tupleFound); qp->SetModified(qp->GetSon(s, 1)); return YIELD; case CLOSE : qp->Close(args[0].addr); if(local.addr) { localTransport = (LocalTransport*) local.addr; delete localTransport; local.setAddr(0); } return 0; } return 0; } /* 2.24.3 Specification of operator ~deletesearch~ */ const string deleteSearchSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" " "\"Example\" ) " "( stream(tuple(x)) x rel(tuple(x))" " -> stream(tuple(x@[TID:tid]))] " "" "_ _ deletesearch" "Deletes all tuples with the same values as tuples" "of the stream from the relation. " "query alteStaedte feed " "staedte deletesearch consume" "" ") )"; /* 2.24.4 Definition of operator ~deletesearch~ */ Operator extreldeletesearch ( "deletesearch", // name deleteSearchSpec, // specification deleteSearchRelValueMap, // value mapping Operator::SimpleSelect, // trivial selection function insertDeleteRelTypeMap<0> // type mapping ); /* 2.25 Operator ~deletedirect~ Deletes each tuple from the inputstream directly from the relation. Precondition is that the tuples of the inputstream are tuples from the relation that shall be updated. Returns a stream of tuples which is basically the stream of deleted tuples but each tuple extended by an attribute of type 'tid' which is the tupleidentifier of the deleted tuple in the updated relation. 2.25.2 Value mapping function of operator ~deletedirect~ */ int deleteDirectRelValueMap(Word* args, Word& result, int message, Word& local, Supplier s) { Word t; Tuple* tup; GenericRelation* relation; TupleType *resultTupleType; ListExpr resultType; switch (message) { case OPEN : qp->Open(args[0].addr); resultType = GetTupleResultType( s ); resultTupleType = new TupleType( nl->Second( resultType ) ); local.setAddr( resultTupleType ); return 0; case REQUEST : resultTupleType = (TupleType*) local.addr; relation = (GenericRelation*)(args[1].addr); assert(relation != 0); qp->Request(args[0].addr,t); if (qp->Received(args[0].addr)) { tup = (Tuple*)t.addr; Tuple *newTuple = new Tuple( resultTupleType ); for( int i = 0; i < tup->GetNoAttributes(); i++ ) newTuple->PutAttribute( i, tup->GetAttribute( i )->Clone() ); const TupleId& tid = tup->GetTupleId(); Attribute* tidAttr = new TupleIdentifier(true,tid); newTuple->PutAttribute(tup->GetNoAttributes(), tidAttr); relation->DeleteTuple(tup); tup->DeleteIfAllowed(); result.setAddr(newTuple); qp->SetModified(qp->GetSon(s, 1)); return YIELD; } else return CANCEL; case CLOSE : qp->Close(args[0].addr); if(local.addr) { resultTupleType = (TupleType*) local.addr; resultTupleType->DeleteIfAllowed(); local.setAddr(0); } return 0; } return 0; } /* 2.25.3 Specification of operator ~deletedirect~ */ const string deleteDirectSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" " "\"Example\" ) " "( stream(tuple(x)) x rel(tuple(x))" " -> stream(tuple(x@[TID:tid]))] " "" "_ _ deletedirect" "Deletes directly all tuples of the stream " "from the relation." "query staedte feed filter [.SName = 'Hagen']" "staedte deletedirect consume" "" ") )"; /* 2.25.4 Definition of operator ~deletedirect~ */ Operator extreldeletedirect ( "deletedirect", // name deleteDirectSpec, // specification deleteDirectRelValueMap, // value mapping Operator::SimpleSelect, // trivial selection function insertDeleteRelTypeMap<0> // type mapping ); /* 2.26 Operator ~deletesearchsave~ Deletes each tuple from the relation which attribut-values are exactly the same as those ones of a tuple of the inputstream. Returns a stream of tuples which is basically the stream of deleted tuples but each tuple extended by an attribute of type 'tid' which is the tupleidentifier of the deleted tuple in the updated relation. In addition all the tuples of the resultstream are inserted into the auxiliary relation which is given as the third argument. 2.26.0 General Type mapping function of operators ~deletesearchsave~, and ~deletedirectsave~ General Type mapping ~deletesearchsave~ and ~deletedirectsave~ ---- (stream X) (rel X) (rel (tuple ((a1 x1) ... (an xn) (TID tid)))) -> (stream (tuple ((a1 x1) ... (an xn) (TID tid)))) where X = (tuple ((a1 x1) ... (an xn))) ---- */ ListExpr deleteSaveRelTypeMap( ListExpr& args, string opName ) { ListExpr first, second, third, rest,listn,lastlistn, outList; string argstr, argstr2; if(nl->ListLength(args)!=3){ return listutils::typeError("three arguments expected"); } // Check inputstream first = nl->First(args); second = nl->Second(args); third = nl->Third(args); if(!listutils::isTupleStream(first)){ return listutils::typeError("first argument has to be a tuple stream"); } if(!listutils::isRelDescription(second) && !listutils::isOrelDescription(second)){ return listutils::typeError("second argument has to be of type rel " "or orel"); } if(!listutils::isRelDescription(third)){ return listutils::typeError("third argument must be a relation"); } if(!nl->Equal(nl->Second(first),nl->Second(second))){ return listutils::typeError("tuple types of the first two " "arguments must be equal"); } rest = nl->Second(nl->Second(second)); listn = nl->OneElemList(nl->First(rest)); 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()))); if(!nl->Equal(listn,nl->Second(nl->Second(third)))){ return listutils::typeError("attribute list of the third argument " "must be equal to the attribute list of the first element " "with an additional tid attribute"); } outList = nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()), nl->TwoElemList(nl->SymbolAtom(Tuple::BasicType()),listn)); return outList; } /* 2.26.1 Type Mapping for operator ~deletesearchsave~ */ ListExpr deleteSearchSaveRelTypeMap(ListExpr args) { return deleteSaveRelTypeMap(args, "deletesearchsave"); } /* 2.26.2 Value mapping function of operator ~deletesearchsave~ */ int deleteSearchSaveRelValueMap(Word* args, Word& result, int message, Word& local, Supplier s) { Word t; Tuple* tup; Tuple* nextTup; Tuple* newTuple; GenericRelation* relation; Relation* auxRelation; GenericRelationIterator* iter; ListExpr resultType; vector* nextBucket; struct LocalTransport { LocalTransport(): deletedTuples( new vector() ), hashTable( new vector*>(256) ), resultTupleType( 0 ) { for (int i = 0; i < 256; i++) (*hashTable)[i] = new vector(); } ~LocalTransport() { for( vector::iterator i = deletedTuples->begin(); i != deletedTuples->end(); i++ ) { (*i)->DeleteIfAllowed(); } delete deletedTuples; for (int i = 0; i < 256; i++) { for( vector::iterator j = (*hashTable)[i]->begin(); j != (*hashTable)[i]->end(); j++ ) { (*j)->DeleteIfAllowed(); } delete (*hashTable)[i]; } delete hashTable; resultTupleType->DeleteIfAllowed(); } vector* deletedTuples; vector*>* hashTable; TupleType* resultTupleType; } *localTransport; size_t hashValue ; bool tupleFound; switch (message) { case OPEN : qp->Open(args[0].addr); localTransport = new LocalTransport(); relation = (GenericRelation*)(args[1].addr); assert(relation != 0); iter = relation->MakeScan(); nextTup = iter->GetNextTuple(); while (!iter->EndOfScan()) { hashValue = 0; for( int i = 0; i < nextTup->GetNoAttributes(); i++ ) hashValue += ((Attribute*) (nextTup->GetAttribute(i)))->HashValue(); nextBucket = localTransport->hashTable->operator[](hashValue % 256); nextBucket->push_back(nextTup); nextTup = iter->GetNextTuple(); } delete iter; resultType = GetTupleResultType( s ); localTransport->resultTupleType = new TupleType( nl->Second( resultType ) ); local.setAddr( localTransport ); return 0; case REQUEST : qp->SetModified(qp->GetSon(s, 1)); qp->SetModified(qp->GetSon(s, 2)); localTransport = (LocalTransport*) local.addr; // Check if already deleted duplicates have to be given to // the outputstream if (!localTransport->deletedTuples->empty()) { newTuple = localTransport->deletedTuples->back(); localTransport->deletedTuples->pop_back(); result.setAddr(newTuple); return YIELD; } // No more duplicate left over to send to the outputstream relation = (Relation*)(args[1].addr); assert(relation != 0); auxRelation = (Relation*)(args[2].addr); assert(auxRelation != 0); tupleFound = false; // tupleFound will stay false until a tuple with the same // values as one of the inputtuples is found while (! tupleFound) { qp->Request(args[0].addr,t); if (qp->Received(args[0].addr)) { tup = (Tuple*)t.addr; hashValue = 0; for( int i = 0; i < tup->GetNoAttributes(); i++ ) hashValue += ((Attribute*) (tup->GetAttribute(i)))->HashValue(); SortOrderSpecification full; for( int i = 0; i < tup->GetNoAttributes(); i++ ) full.push_back(pair (i+1,false)); TupleCompareBy compare(full); // Get the right hash-bucket nextBucket = localTransport->hashTable->operator[](hashValue % 256); // Check all tuples in the bucket for (size_t j = 0; j < nextBucket->size(); j++) { nextTup = nextBucket->operator[](j); if (nextTup != 0) { if(!compare(nextTup,tup) && !compare(tup,nextTup)) { newTuple = new Tuple(localTransport->resultTupleType); assert( newTuple->GetNoAttributes() == nextTup->GetNoAttributes() +1 ); for( int i = 0; i < nextTup->GetNoAttributes(); i++ ) newTuple->PutAttribute( i, (nextTup->GetAttribute(i))->Clone() ); const TupleId& tid = nextTup->GetTupleId(); Attribute* tidAttr = new TupleIdentifier(true,tid); newTuple->PutAttribute( nextTup->GetNoAttributes(), tidAttr); relation->DeleteTuple(nextTup); auxRelation->AppendTuple(newTuple); newTuple->IncReference(); localTransport->deletedTuples->push_back(newTuple); } } } // Set result if at least one tuple was deleted if (!localTransport->deletedTuples->empty()) { newTuple = localTransport->deletedTuples->back(); newTuple->DeleteIfAllowed(); localTransport->deletedTuples->pop_back(); result.setAddr(newTuple); tupleFound = true; } tup->DeleteIfAllowed(); } else// if (qp->Received(args[0].addr)) return CANCEL; }// while (! tupleFound); return YIELD; case CLOSE : qp->Close(args[0].addr); if(local.addr) { localTransport = (LocalTransport*) local.addr; delete localTransport; local.setAddr(0); } return 0; } return 0; } /* 2.26.3 Specification of operator ~deletesearchsave~ */ const string deleteSearchSaveSpec = "(( \"Signature\" \"Syntax\" \"Meaning\" " "\"Example\" ) " "(stream(tuple(x)) x rel(tuple(x)) x rel(tuple(x@[TID:tid]))" " -> stream(tuple(x@[TID:tid]))] " "" "_ _ _deletesearchsave" "Like deletesearch but appends all result-tuples" "to the auxiliary relation." "query alteStaedte feed staedte staedteD deletesearchsave " "consume" "" ") )"; /* 2.26.4 Definition of operator ~deletesearchsave~ */ Operator extreldeletesearchsave ( "deletesearchsave", // name deleteSearchSaveSpec, // specification deleteSearchSaveRelValueMap, // value mapping Operator::SimpleSelect, // trivial selection function deleteSearchSaveRelTypeMap // type mapping ); /* 2.27 Operator ~deletedirectsave~ Deletes directly each tuple of the inputstream from the relation. Precondition is that all tuples of the inputstream are originally tuples of the relation that shall be updated. Returns a stream of tuples which is basically the stream of deleted tuples but each tuple extended by an attribute of type 'tid' which is the tupleidentifier of the deleted tuple in the updated relation.In addition all the tuples of the resultstream are inserted into the auxiliary relation which is given as the third argument. 2.27.1 Type Mapping for operator ~deletedirectsave~ */ ListExpr deleteDirectSaveRelTypeMap(ListExpr args) { return deleteSaveRelTypeMap(args, "deletedirectsave"); } /* 2.27.2 Value mapping function of operator ~deletedirectsave~ */ int deleteDirectSaveRelValueMap(Word* args, Word& result, int message, Word& local, Supplier s) { Word t; Tuple* tup; GenericRelation* relation; Relation* auxRelation; TupleType *resultTupleType; ListExpr resultType; switch (message) { case OPEN : qp->Open(args[0].addr); resultType = GetTupleResultType( s ); resultTupleType = new TupleType( nl->Second( resultType ) ); local.setAddr( resultTupleType ); return 0; case REQUEST : resultTupleType = (TupleType*) local.addr; relation = (GenericRelation*)(args[1].addr); assert(relation != 0); auxRelation = (Relation*)(args[2].addr); assert(auxRelation != 0); qp->Request(args[0].addr,t); if (qp->Received(args[0].addr)) { tup = (Tuple*)t.addr; Tuple *newTuple = new Tuple( resultTupleType ); assert( newTuple->GetNoAttributes() == tup->GetNoAttributes() +1 ); for( int i = 0; i < tup->GetNoAttributes(); i++ ) newTuple->PutAttribute( i, tup->GetAttribute( i )->Clone() ); const TupleId& tid = tup->GetTupleId(); Attribute* tidAttr = new TupleIdentifier(true,tid); newTuple->PutAttribute( tup->GetNoAttributes(), tidAttr); relation->DeleteTuple(tup); qp->SetModified(qp->GetSon(s, 1)); qp->SetModified(qp->GetSon(s, 2)); auxRelation->AppendTuple(newTuple); result.setAddr(newTuple); tup->DeleteIfAllowed(); return YIELD; } else return CANCEL; case CLOSE : qp->Close(args[0].addr); if(local.addr) { resultTupleType = (TupleType*) local.addr; resultTupleType->DeleteIfAllowed(); local.setAddr(0); } return 0; } return 0; } /* 2.27.3 Specification of operator ~deletedirectsave~ */ const string deleteDirectSaveSpec = "(( \"Signature\" \"Syntax\" \"Meaning\" " "\"Example\" ) " "(stream(tuple(x)) x rel(tuple(x)) x rel(tuple(x@[TID:tid]))" " -> stream(tuple(x@[TID:tid]))] " "" "_ _ _deletedirectsave" "Like 'deletedirect' but appends all result-tuples " "to the auxiliary relation." "query staedte feed filter [.Bev > 200000] " "staedte staedteD deletedirectsave consume" "" ") )"; /* 2.27.4 Definition of operator ~deletedirectsave~ */ Operator extreldeletedirectsave ( "deletedirectsave", // name deleteDirectSaveSpec, // specification deleteDirectSaveRelValueMap, // value mapping Operator::SimpleSelect, // trivial selection function deleteDirectSaveRelTypeMap // type mapping ); /* 2.28 Operator ~inserttuple~ Inserts a new tuple with the attribute-values of the second argument into the relation. Returns a stream of one tuple which is basically the same as the inserted tuple but extended by an attribute of type 'tid' which is the tupleidentifier of the inserted tuple in the extended relation. 2.28.1 Type mapping function of operator ~inserttuple~ Type mapping ~inserttuple~ on a relation ---- (rel(tuple(x))) x [t1,... tn] -> stream(tuple(x@[TID:tid]))) ---- */ ListExpr insertTupleTypeMap(ListExpr args) { ListExpr first,second, rest, rest2, listn, lastlistn, outList; string argstr="",valueString; if(nl->ListLength(args)!=2){ return listutils::typeError("two arguments expected"); } first = nl->First(args); second = nl->Second(args); if(!listutils::isRelDescription(first) && !listutils::isOrelDescription(first)){ return listutils::typeError("rel or orel as first arg expected"); } 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"); } rest = nl->Second(nl->Second(first)); rest2 = second; while (!(nl->IsEmpty(rest))) { if(!nl->Equal(nl->Second(nl->First(rest)),nl->First(rest2))){ return listutils::typeError("type mismatch in attribute " "list and update list"); } rest = nl->Rest(rest); rest2 = nl->Rest(rest2); } // build resultlist rest = nl->Second(nl->Second(first)); listn = nl->OneElemList(nl->First(rest)); 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()))); outList = nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()), nl->TwoElemList(nl->SymbolAtom(Tuple::BasicType()),listn)); return outList; } /* 2.28.2 Value mapping function of operator ~inserttuple~ */ int insertTupleRelValueMap(Word* args, Word& result, int message, Word& local, Supplier s) { Word attrValue; Tuple* insertTuple; Tuple* resultTuple; GenericRelation* relation; TupleType *resultTupleType; ListExpr resultType; TupleType* insertTupleType; ListExpr insertType; ListExpr rest; ListExpr last; bool* firstcall; Supplier supplier, supplier1; Attribute* attr; switch (message) { case OPEN : firstcall = new bool; *firstcall = true; local.setAddr( firstcall ); return 0; case REQUEST : firstcall = (bool*) local.addr; if (*firstcall) { *firstcall = false; resultType = GetTupleResultType( s ); resultTupleType = new TupleType( nl->Second( resultType ) ); relation = (GenericRelation*)(args[0].addr); assert(relation != 0); resultTuple = new Tuple( resultTupleType ); rest = nl->Second(nl->Second(resultType)); insertType = nl->OneElemList(nl->First(rest)); 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); insertTupleType = new TupleType( insertType ); insertTuple = new Tuple( insertTupleType ); supplier = args[1].addr; for( int i = 0; i < resultTuple->GetNoAttributes()-1; i++ ) { supplier1 = qp->GetSupplier(supplier, i); qp->Request(supplier1,attrValue); attr = (Attribute*) attrValue.addr; resultTuple->PutAttribute(i,attr->Clone()); insertTuple->CopyAttribute(i,resultTuple,i); } relation->AppendTuple(insertTuple); qp->SetModified(qp->GetSon(s, 0)); const TupleId& tid = insertTuple->GetTupleId(); Attribute* tidAttr = new TupleIdentifier(true,tid); resultTuple->PutAttribute( resultTuple->GetNoAttributes() -1, tidAttr); result.setAddr(resultTuple); insertTuple->DeleteIfAllowed(); resultTupleType->DeleteIfAllowed(); insertTupleType->DeleteIfAllowed(); return YIELD; } else return CANCEL; case CLOSE : if(local.addr) { firstcall = (bool*) local.addr; delete firstcall; local.setAddr(0); } return 0; } return 0; } /* 2.28.3 Specification of operator ~inserttuple~ */ const string insertTupleSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" " "\"Example\" ) " "( rel(tuple(x))) x [t1 ... tn]" " -> stream(tuple(x@[TID:tid]))] " "" " _ inserttuple [list]" "Inserts a new tuple with the values from" " the second argument-list into the relation. " "query staedte inserttuple['Kassel', 200000, 50000] " "consume" "" ") )"; /* 2.28.4 Definition of operator ~inserttuple~ */ Operator extrelinserttuple ( "inserttuple", // name insertTupleSpec, // specification insertTupleRelValueMap, // value mapping Operator::SimpleSelect, // trivial selection function insertTupleTypeMap // type mapping ); /* 2.29 Operator ~inserttuplesave~ Inserts a new tuple with the attribute-values of the second argument into the relation. Returns a stream of one tuple which is basically the same as the inserted tuple but extended by an attribute of type int which is the tupleidentificator of the inserted tuple in the extended relation. In addition the tuple of the resultstream is inserted into the relation which is given by the second argument. 2.29.1 Type mapping function of operator ~inserttuplesave~ Type mapping ~inserttuplesave~ on a relation ---- (rel(tuple(x))) x (rel(tuple(x@[TID:tid]))) x [t1 ... tn] -> stream(tuple(x@[TID:tid]))) ---- */ ListExpr insertTupleSaveTypeMap(ListExpr args) { ListExpr first,second, third, rest, rest2, listn, lastlistn, outList; string argstr="",valueString, argstr2; if(nl->ListLength(args)!=3){ return listutils::typeError("three arguments expecetd"); } first = nl->First(args); second = nl->Second(args); third= nl->Third(args); if(!listutils::isRelDescription(first) && !listutils::isOrelDescription(first)){ return listutils::typeError("first argument must be a relation"); } if(nl->ListLength(nl->Second(nl->Second(first)))!=nl->ListLength(third)){ return listutils::typeError("number of attributes differs from number " "of update value"); } if(!listutils::isRelDescription(second)){ return listutils::typeError("second argument must be a relation"); } // updatrelation at the same positions are the same rest = nl->Second(nl->Second(first)); rest2 = third; while (!(nl->IsEmpty(rest))) { if(!nl->Equal(nl->Second(nl->First(rest)),nl->First(rest2))){ return listutils::typeError("type mismatch in attribute list" " and update list"); } rest = nl->Rest(rest); rest2 = nl->Rest(rest2); } // build resultlist rest = nl->Second(nl->Second(first)); listn = nl->OneElemList(nl->First(rest)); 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()))); // Check if result-tupletype and type of the auxiliary relation // are the same if(!nl->Equal(listn, nl->Second(nl->Second(second)))){ return listutils::typeError("second argument must be a relation having " " the same attributes as the first relation and an additional " " tid attribute "); } outList = nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()), nl->TwoElemList(nl->SymbolAtom(Tuple::BasicType()),listn)); return outList; } /* 2.29.2 Value mapping function of operator ~inserttuplesave~ */ int insertTupleSaveRelValueMap(Word* args, Word& result, int message, Word& local, Supplier s) { Word attrValue; Tuple* insertTuple; Tuple* resultTuple; GenericRelation* relation; Relation* auxRelation; TupleType *resultTupleType; ListExpr resultType; TupleType* insertTupleType; ListExpr insertType; ListExpr rest; ListExpr last; bool* firstcall; Supplier supplier, supplier1; Attribute* attr; switch (message) { case OPEN : firstcall = new bool; *firstcall = true; local.setAddr( firstcall ); return 0; case REQUEST : firstcall = (bool*) local.addr; if (*firstcall) { *firstcall = false; resultType = GetTupleResultType( s ); resultTupleType = new TupleType( nl->Second( resultType ) ); relation = (GenericRelation*)(args[0].addr); assert(relation != 0); auxRelation = (Relation*)(args[1].addr); assert(auxRelation != 0); resultTuple = new Tuple( resultTupleType ); rest = nl->Second(nl->Second(resultType)); insertType = nl->OneElemList(nl->First(rest)); 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); insertTupleType = new TupleType( insertType ); insertTuple = new Tuple( insertTupleType ); supplier = args[2].addr; for( int i = 0; i < resultTuple->GetNoAttributes()-1; i++ ) { supplier1 = qp->GetSupplier(supplier, i); qp->Request(supplier1,attrValue); attr = (Attribute*) attrValue.addr; resultTuple->PutAttribute(i,attr->Clone()); insertTuple->CopyAttribute(i,resultTuple,i); } relation->AppendTuple(insertTuple); qp->SetModified(qp->GetSon(s, 0)); qp->SetModified(qp->GetSon(s, 1)); const TupleId& tid = insertTuple->GetTupleId(); Attribute* tidAttr = new TupleIdentifier(true,tid); resultTuple->PutAttribute( resultTuple->GetNoAttributes() -1, tidAttr); auxRelation->AppendTuple(resultTuple); result.setAddr(resultTuple); insertTuple->DeleteIfAllowed(); resultTupleType->DeleteIfAllowed(); insertTupleType->DeleteIfAllowed(); return YIELD; } else return CANCEL; case CLOSE : if(local.addr) { firstcall = (bool*) local.addr; delete firstcall; local.setAddr(0); } return 0; } return 0; } /* 2.29.3 Specification of operator ~inserttuplesave~ */ const string insertTupleSaveSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" " "\"Example\" ) " "( rel(tuple(x)) x rel(tuple(x@[TID:tid])) x [t1 ... tn]" " -> stream(tuple(x@[TID:tid]))] " "" " _ _ inserttuplesave [list]" "Like `inserttuple` but appends the result-tuple " "to the auxiliary relation " "query staedte staedteI " "inserttuplesave['Kassel', 200000, 50000] consume" "" ") )"; /* 2.29.4 Definition of operator ~inserttuplesave~ */ Operator extrelinserttuplesave ( "inserttuplesave", // name insertTupleSaveSpec, // specification insertTupleSaveRelValueMap, // value mapping Operator::SimpleSelect, // trivial selection function insertTupleSaveTypeMap // type mapping ); /* 2.18 Operator ~updatedirect~ Updates each input tuple by replacing the attribute-values of the attributes given by their names in the function-argumentlist with the new values received from the corresponding functions. Precondition is that all tuples of the inpustream are originally tuples of the updated relation. The updated tuple is made persistent and as the resultstream tuples are i returned that contain the new values in first places, then all old values and finally the TupleIdentifier of the updated tuple. 2.18.0 General Type mapping function of operators ~updatedirect~, and ~updatesearch~ Type mapping for ~updatedirect~ and ~updatesearch~ is ---- (stream X) (rel X) ((ai1 (map x xi1)) ... (aij (map x xij)) -> (stream (tuple ((a1 x1) ... (an xn) (a1_old x1) ... (an_old xn)(TID tid)))) where X = (tuple ((a1 x1) ... (an xn))) and ai1 - aij in (a1 .. an) ---- */ ListExpr updateTypeMap( ListExpr& args, string opName ) { ListExpr first, second,third,rest, listn, lastlistn, first2, second2, firstr,attrType, numberList, lastNumberList,oldAttribute, outlist; first= second = third = rest = listn = lastlistn = first2 = second2 = firstr =attrType = numberList = lastNumberList = oldAttribute = outlist = nl->TheEmptyList(); int attrIndex, noAttrs ; bool firstcall = true; string argstr, argstr2, argstr3, oldName; if(nl->ListLength(args)!=3){ return listutils::typeError("three arguments expected"); } first = nl->First(args); second = nl->Second(args); third = nl->Third(args); if(!listutils::isTupleStream(first)){ return listutils::typeError("tuple stream expected"); } if(!listutils::isRelDescription(second) && !listutils::isOrelDescription(second)){ return listutils::typeError("second argument must be a relation"); } if(!nl->Equal(nl->Second(nl->Second(first)), nl->Second(nl->Second(second)))){ return listutils::typeError("tuple types of first and second arg differ"); } if(nl->ListLength(third<1)){ return listutils::typeError("third arg must be a list of maps"); } rest = third; noAttrs = nl->ListLength(third); // Go through all functions while (!(nl->IsEmpty(rest))) { firstr = nl->First(rest); rest = nl->Rest(rest); first2 = nl->First(firstr); second2 = nl->Second(firstr); // Is it a function? if(!listutils::isMap<1>(second2)){ return listutils::typeError("not a map found"); } if(!nl->Equal(nl->Second(first),nl->Second(second2))){ return listutils::typeError("argument of map is wrong"); } // Is the name of the attribute that shall be computed by the // function a valid name if(!listutils::isSymbol(first2)){ return listutils::typeError("not a valid attribute name:" + nl->ToString(first2)); } nl->WriteToString(argstr, first2); 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(second2))){ return listutils::typeError("result of the map and attribute" " type differ"); } // Construct a list with all indices of the changed attributes // in the inputstream to be appended to the resultstream if (firstcall) { numberList = nl->OneElemList(nl->IntAtom(attrIndex)); lastNumberList = numberList; firstcall = false; } else { lastNumberList = nl->Append( lastNumberList, nl->IntAtom(attrIndex)); } } // build first part of the resultstream rest = nl->Second(nl->Second(first)); listn = nl->OneElemList(nl->First(rest)); lastlistn = listn; rest = nl->Rest(rest); while (!(nl->IsEmpty(rest))) { lastlistn = nl->Append(lastlistn,nl->First(rest)); rest = nl->Rest(rest); } // build second part of the resultstream rest = nl->Second(nl->Second(first)); 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); } lastlistn = nl->Append( lastlistn, nl->TwoElemList( nl->SymbolAtom("TID"), nl->SymbolAtom(TupleIdentifier::BasicType()))); outlist = nl->ThreeElemList( nl->SymbolAtom(Symbol::APPEND()), nl->TwoElemList( nl->IntAtom(noAttrs), numberList), nl->TwoElemList( nl->SymbolAtom(Symbol::STREAM()), nl->TwoElemList( nl->SymbolAtom(Tuple::BasicType()), listn))); return outlist; } /* 2.30.1 Type mapping function of operator ~updatedirect~ */ ListExpr updateDirectRelTypeMap(ListExpr args) { return updateTypeMap(args, "updatedirect"); } /* 2.30.2 Value mapping function of operator ~updatedirect~ */ int UpdateDirect(Word* args, Word& result, int message, Word& local, Supplier s) { Word t, value, elem; Tuple* tup; Supplier supplier, supplier2, supplier3, son; int noOfAttrs, index; ArgVectorPointer funargs; TupleType *resultTupleType; ListExpr resultType; GenericRelation* relation; Attribute* newAttribute; switch (message) { case OPEN : qp->Open(args[0].addr); resultType = GetTupleResultType( s ); resultTupleType = new TupleType( nl->Second( resultType ) ); local.setAddr( resultTupleType ); return 0; case REQUEST : resultTupleType = (TupleType *)local.addr; relation = (GenericRelation*) args[1].addr; qp->Request(args[0].addr,t); if (qp->Received(args[0].addr)) { tup = (Tuple*)t.addr; Tuple *newTuple = new Tuple( resultTupleType ); // Copy the attributes from the old tuple assert( newTuple->GetNoAttributes() == 2 * tup->GetNoAttributes() + 1); for (int i = 0; i < tup->GetNoAttributes(); i++) newTuple->PutAttribute( tup->GetNoAttributes()+i, tup->GetAttribute(i)->Clone()); // Number of attributes to be replaced noOfAttrs = ((CcInt*)args[3].addr)->GetIntval(); // Supplier for the functions supplier = args[2].addr; vector* changedIndices = new vector(noOfAttrs); vector* newAttrs = new vector(noOfAttrs); for (int i=1; i <= noOfAttrs; i++) { // Get next appended index son = qp->GetSupplier(args[4].addr, i-1); qp->Request(son, elem); index = ((CcInt*)elem.addr)->GetIntval() -1; (*changedIndices)[i-1] = index; // Get next function definition supplier2 = qp->GetSupplier(supplier, i-1); // Get the function supplier3 = qp->GetSupplier(supplier2, 1); funargs = qp->Argument(supplier3); ((*funargs)[0]).setAddr(tup); qp->Request(supplier3,value); newAttribute = ((Attribute*)value.addr)->Clone(); (*newAttrs)[i-1] = newAttribute; } relation->UpdateTuple(tup,*changedIndices,*newAttrs); qp->SetModified(qp->GetSon(s, 1)); for (int i = 0; i < tup->GetNoAttributes(); i++) newTuple->CopyAttribute( i, tup, i ); const TupleId& tid = tup->GetTupleId(); Attribute* tidAttr = new TupleIdentifier(true,tid); newTuple->PutAttribute( newTuple->GetNoAttributes() - 1, tidAttr ); delete changedIndices; delete newAttrs; tup->DeleteIfAllowed(); result.setAddr(newTuple); return YIELD; } else return CANCEL; case CLOSE : qp->Close(args[0].addr); if(local.addr) { resultTupleType = (TupleType *)local.addr; resultTupleType->DeleteIfAllowed(); local.setAddr(0); } return 0; } return 0; } /* 2.18.3 Specification of operator ~updatedirect~ */ const string UpdateDirectSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" " "\"Example\" ) " "( stream(tuple(x)) x rel(tuple(x)) x [(a1, (tuple(x)" " -> d1)) ... (an, (tuple(x) -> dn))] -> " "stream(tuple(x @ [x1_old t1] @...[xn_old tn] @ [TID tid])))" "" "_ _ updatedirect [funlist]" "Updates each input tuple by replacing " "attributes as specified in the parameter" " funlist." "query ten feed ten updatedirect [nr: " ".nr * 5] consume" "" ") )"; /* 2.18.4 Definition of operator ~updatedirect~ */ Operator extrelupdatedirect ( "updatedirect", // name UpdateDirectSpec, // specification UpdateDirect, // value mapping Operator::SimpleSelect, // trivial selection function updateDirectRelTypeMap // type mapping ); /* 2.18 Operator ~updatesearch~ For each input-tuple searches for tuples in the relation with the same values as the input-tuple. Each found tuple is updated by replacing the attribute-values of the attributes given by their names in the function-argumentlist with the new values received from the corresponding functions. The updated tuple is made persistent and as the resultstream tuples are returned that contain the new values in first places, then all old values and finally the TupleIdentifier of the updated tuple. 2.18.1 Type mapping function of operator ~updatesearch~ */ ListExpr updateSearchRelTypeMap(ListExpr args) { return updateTypeMap(args, "updatesearch"); } /* 2.18.2 Value mapping function of operator ~updatesearch~ */ int UpdateSearch(Word* args, Word& result, int message, Word& local, Supplier s) { Word t, value, elem; Tuple* tup; Tuple* newTuple; Tuple* nextTup; Supplier supplier, supplier2, supplier3, son; int noOfAttrs, index; ArgVectorPointer funargs; ListExpr resultType; GenericRelation* relation; GenericRelationIterator* iter; Attribute* newAttribute; vector* nextBucket; struct LocalTransport { LocalTransport(): updatedTuples( new vector() ), hashTable( new vector*>(256) ), resultTupleType( 0 ) { for (int i = 0; i < 256; i++) (*hashTable)[i] = new vector(); } ~LocalTransport() { for( vector::iterator i = updatedTuples->begin(); i != updatedTuples->end(); i++ ) { (*i)->DeleteIfAllowed(); } delete updatedTuples; for (int i = 0; i < 256; i++) { for( vector::iterator j = (*hashTable)[i]->begin(); j != (*hashTable)[i]->end(); j++ ) { (*j)->DeleteIfAllowed(); } delete (*hashTable)[i]; } delete hashTable; resultTupleType->DeleteIfAllowed(); } vector* updatedTuples; vector*>* hashTable; TupleType* resultTupleType; } *localTransport; size_t hashValue ; bool tupleFound; switch (message) { case OPEN : qp->Open(args[0].addr); localTransport = new LocalTransport(); relation = (GenericRelation*)(args[1].addr); assert(relation != 0); iter = relation->MakeScan(); nextTup = iter->GetNextTuple(); // Fill hashtable while (!iter->EndOfScan()) { hashValue = 0; for( int i = 0; i < nextTup->GetNoAttributes(); i++ ) hashValue += ((Attribute*) (nextTup->GetAttribute(i)))->HashValue(); nextBucket = localTransport->hashTable->operator[](hashValue % 256); nextBucket->push_back(nextTup); nextTup = iter->GetNextTuple(); } delete iter; resultType = GetTupleResultType( s ); localTransport->resultTupleType = new TupleType( nl->Second( resultType ) ); local.setAddr( localTransport ); return 0; case REQUEST : localTransport = (LocalTransport*) local.addr; // Check if an already updated duplicate of the last // inputtuple has to be given to the resultstream first if (!localTransport->updatedTuples->empty()) { newTuple = localTransport->updatedTuples->back(); newTuple->DeleteIfAllowed(); localTransport->updatedTuples->pop_back(); result.setAddr(newTuple); return YIELD; } // No more duplicates to send to the resultstream relation = (GenericRelation*) args[1].addr; tupleFound = false; // tupleFound will stay false until a tuple with the same // values as the inputtuple was found and updated while (! tupleFound) { qp->Request(args[0].addr,t); if (qp->Received(args[0].addr)) { tup = (Tuple*)t.addr; hashValue = 0; for( int i = 0; i < tup->GetNoAttributes(); i++ ) hashValue += ((Attribute*) (tup->GetAttribute(i)))->HashValue(); SortOrderSpecification full; for( int i = 0; i < tup->GetNoAttributes(); i++ ) full.push_back(pair (i+1,false)); TupleCompareBy compare(full); // Get the right bucket from the hashtable nextBucket = localTransport->hashTable->operator[](hashValue % 256); // Get all tuples from the bucket that have the same // attributevalues as the inputtuple for (size_t j = 0; j < nextBucket->size(); j++) { nextTup = nextBucket->operator[](j); if (nextTup != 0) { if(!compare(nextTup,tup) && !compare(tup,nextTup)) { newTuple = new Tuple(localTransport->resultTupleType); assert( newTuple->GetNoAttributes() == 2 * nextTup->GetNoAttributes() + 1); for (int i = 0; i < nextTup->GetNoAttributes(); i++) newTuple->PutAttribute( nextTup->GetNoAttributes()+i, nextTup->GetAttribute(i)->Clone()); noOfAttrs = ((CcInt*)args[3].addr)->GetIntval(); // Supplier for the functions supplier = args[2].addr; vector* changedIndices = new vector(noOfAttrs); vector* newAttrs = new vector(noOfAttrs); for (int i=1; i <= noOfAttrs; i++) { // Supplier for the next index son = qp->GetSupplier(args[4].addr, i-1); qp->Request(son, elem); index = ((CcInt*)elem.addr)->GetIntval() -1; (*changedIndices)[i-1] = index; // Suppliers for the next function supplier2 = qp->GetSupplier(supplier, i-1); supplier3 = qp->GetSupplier(supplier2, 1); funargs = qp->Argument(supplier3); ((*funargs)[0]).setAddr(nextTup); qp->Request(supplier3,value); newAttribute = ((Attribute*)value.addr)->Clone(); (*newAttrs)[i-1] = newAttribute; } relation->UpdateTuple( nextTup,*changedIndices,*newAttrs); qp->SetModified(qp->GetSon(s, 1)); for (int i = 0; i < nextTup->GetNoAttributes(); i++) newTuple->CopyAttribute( i, nextTup, i ); const TupleId& tid = nextTup->GetTupleId(); Attribute* tidAttr = new TupleIdentifier(true,tid); newTuple->PutAttribute( newTuple->GetNoAttributes() - 1, tidAttr ); delete changedIndices; delete newAttrs; newTuple->IncReference(); localTransport->updatedTuples->push_back(newTuple); } } } // Check if at least one tuple was updated if (!localTransport->updatedTuples->empty()) { newTuple = localTransport->updatedTuples->back(); newTuple->DeleteIfAllowed(); localTransport->updatedTuples->pop_back(); result.setAddr(newTuple); tupleFound = true; } tup->DeleteIfAllowed(); } else// if (qp->Received(args[0].addr)) return CANCEL; }// while (! tupleFound); return YIELD; case CLOSE : qp->Close(args[0].addr); if(local.addr) { localTransport = (LocalTransport*) local.addr; delete localTransport; local.setAddr(0); } return 0; } return 0; } /* 2.18.3 Specification of operator ~updatesearch~ */ const string UpdateSearchSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" " "\"Example\" ) " "( stream(tuple(x)) x rel(tuple(x)) x [(a1, (tuple(x)" " -> d1)) ... (an, (tuple(x) -> dn))] -> " "stream(tuple(x @ [x1_old t1]@...[xn_old tn] @ [TID tid])))" "" "_ _ updatesearch [funlist]" "Each tuple of the relation with the same values as " "one input tuple is updated." "query staedteUpdate feed staedte updatesearch [Bev: " ".Bev + 1000] consume" "" ") )"; /* 2.18.4 Definition of operator ~updatesearch~ */ Operator extrelupdatesearch ( "updatesearch", // name UpdateSearchSpec, // specification UpdateSearch, // value mapping Operator::SimpleSelect, // trivial selection function updateSearchRelTypeMap // type mapping ); /* 2.18 Operator ~updatedirectsave~ Updates each input tuple by replacing the attribute values of the attributes given by their names in the function-argumentlist with the new values received from the functions. Precondition is that the tuples of the input stream originally belong to the relation that shall be updated. The updated tuple is made persistent and as the resultstream tuples are returned that contain the new values in first places, then all old values and finally the tuple identifier (TID) of the updated tuple. Additionally, the resulting tuples are stored in an auxiliary relation given as the third argument 2.18.0 General Type mapping functions of operators ~updatedirectsave~, and ~updatesearchsave~ Type mapping for ~updatedirectsave~ and ~updatesearchsave~ is ---- (stream X) (rel X) (rel(tuple ((a1 x1) ... (an xn) (a1_old x1) ... (an_old xn)(TID tid)))) ((ai1 (map x xi1)) ... (aij (map x xij))) -> (stream (tuple ((a1 x1) ... (an xn) (a1_old x1) ... (an_old xn)(TID tid)))) where X = (tuple ((a1 x1) ... (an xn))) and i1, ..., ij in {1, ... , n} ---- */ ListExpr updateSaveTypeMap( ListExpr& args, string opName ) { ListExpr first, second,third,fourth, rest, listn, lastlistn, first2, second2, firstr,attrType,numberList, lastNumberList,oldAttribute, outlist; first = second = third = fourth = rest = listn = lastlistn = first2 = second2 = firstr = attrType = numberList = lastNumberList = oldAttribute = outlist = nl->TheEmptyList(); int attrIndex, noAttrs ; bool firstcall = true; string argstr, argstr2,argstr3,oldName; if(nl->ListLength(args)!=4){ return listutils::typeError("four arguments expected"); } first = nl->First(args); second = nl->Second(args); third = nl->Third(args); fourth = nl->Fourth(args); // Check inputstream if(!listutils::isTupleStream(first)){ return listutils::typeError("first argument must be a tuple stream"); } if(!listutils::isRelDescription(second) && !listutils::isOrelDescription(second)){ return listutils::typeError("second argument must be a relation"); } if(!nl->Equal(nl->Second(first),nl->Second(second))){ return listutils::typeError("tuple type of first and" " second argument differ"); } if(!listutils::isRelDescription(third)){ return listutils::typeError("third argument must be a relation"); } if(nl->ListLength(fourth)<1){ return listutils::typeError("fourth argument must be a function list"); } rest = fourth; noAttrs = nl->ListLength(fourth); // Check each update-function while (!(nl->IsEmpty(rest))) { firstr = nl->First(rest); rest = nl->Rest(rest); first2 = nl->First(firstr); second2 = nl->Second(firstr); if(!listutils::isMap<1>(second2)){ return listutils::typeError("found a non function in function list"); } if(!nl->Equal(nl->Second(first), nl->Second(second2))){ return listutils::typeError("tuple type and result type of a" " function differ"); } if(!listutils::isSymbol(first2)){ return listutils::typeError("invalid attribute name found"); } // Is the function attributename a valid name? nl->WriteToString(argstr, first2); attrIndex = listutils::findAttribute(nl->Second(nl->Second(first)), argstr, attrType); if(attrIndex==0){ return listutils::typeError("attribute " + argstr + " unknown"); } if(!nl->Equal(attrType, nl->Third(second2))){ return listutils::typeError("result type of function differs from" " corresponding attribute type"); } // build a list with all indices of the updated attributes in // the update-relation to be appended to the resultstream if (firstcall) { numberList = nl->OneElemList(nl->IntAtom(attrIndex)); lastNumberList = numberList; firstcall = false; } else { lastNumberList = nl->Append( lastNumberList, nl->IntAtom(attrIndex)); } } // build first part of the resultstream rest = nl->Second(nl->Second(first)); listn = nl->OneElemList(nl->First(rest)); lastlistn = listn; rest = nl->Rest(rest); while (!(nl->IsEmpty(rest))) { lastlistn = nl->Append(lastlistn,nl->First(rest)); rest = nl->Rest(rest); } // build second part of the resultstream rest = nl->Second(nl->Second(first)); 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); } lastlistn = nl->Append( lastlistn, nl->TwoElemList( nl->SymbolAtom("TID"), nl->SymbolAtom(TupleIdentifier::BasicType()))); outlist = nl->ThreeElemList( nl->SymbolAtom(Symbol::APPEND()), nl->TwoElemList( nl->IntAtom(noAttrs), numberList), nl->TwoElemList( nl->SymbolAtom(Symbol::STREAM()), nl->TwoElemList( nl->SymbolAtom(Tuple::BasicType()), listn))); // cout << "typemap-result:" << nl->ToString(outlist) << endl; return outlist; } /* 2.30.1 Type mapping function of operator ~updatedirectsave~ */ ListExpr updateDirectSaveRelTypeMap(ListExpr args) { return updateSaveTypeMap(args, "updatedirectsave"); } /* 2.30.2 Value mapping function of operator ~updatedirectsave~ */ int UpdateDirectSave(Word* args, Word& result, int message, Word& local, Supplier s) { Word t, value, elem; t.addr = 0; value.addr = 0; elem.addr = 0; Tuple* tup = 0; Supplier supplier, supplier2, supplier3, son; int noOfAttrs=0, index=0; ArgVectorPointer funargs; TupleType *resultTupleType = 0; ListExpr resultType; GenericRelation* relation = 0; Relation* auxRelation = 0; Attribute* newAttribute = 0; switch (message) { case OPEN : qp->Open(args[0].addr); resultType = GetTupleResultType( s ); resultTupleType = new TupleType( nl->Second( resultType ) ); local.setAddr( resultTupleType ); return 0; case REQUEST : resultTupleType = (TupleType *)local.addr; relation = (GenericRelation*) args[1].addr; auxRelation = (Relation*)(args[2].addr); assert(auxRelation != 0); qp->Request(args[0].addr,t); if (qp->Received(args[0].addr)) { tup = (Tuple*)t.addr; //tup->IncReference(); Tuple *newTuple = new Tuple( resultTupleType ); assert( newTuple->GetNoAttributes() == 2 * tup->GetNoAttributes() + 1); // store old values int the result tuple for (int i = 0; i < tup->GetNoAttributes(); i++) { newTuple->CopyAttribute(i, tup , i); newTuple->CopyAttribute(i, tup , tup->GetNoAttributes()+i); } noOfAttrs = ((CcInt*)args[4].addr)->GetIntval(); // Get the supplier for the updatefunctions supplier = args[3].addr; vector* changedIndices = new vector(noOfAttrs); vector* newAttrs = new vector(noOfAttrs); for (int i=1; i <= noOfAttrs; i++) { // supplier for the next index of an updated attribute son = qp->GetSupplier(args[5].addr, i-1); qp->Request(son, elem); index = ((CcInt*)elem.addr)->GetIntval() -1; (*changedIndices)[i-1] = index; // Suppliers for the next updatefunction supplier2 = qp->GetSupplier(supplier, i-1); supplier3 = qp->GetSupplier(supplier2, 1); funargs = qp->Argument(supplier3); ((*funargs)[0]).setAddr(tup); qp->Request(supplier3,value); newAttribute = ((Attribute*)value.addr)->Clone(); (*newAttrs)[i-1] = newAttribute; // store new value in result tuple newTuple->PutAttribute( index, newAttribute->Copy() ); } // store tid in output tuple const TupleId& tid = tup->GetTupleId(); Attribute* tidAttr = new TupleIdentifier(true,tid); newTuple->PutAttribute( newTuple->GetNoAttributes() - 1, tidAttr); // copy new attribute values into auxTuple Tuple *auxTuple = new Tuple( auxRelation->GetTupleType() ); for (int i=0; i< auxTuple->GetNoAttributes() - 1; i++){ auxTuple->CopyAttribute( i, newTuple, i); } auxTuple->PutAttribute(auxTuple->GetNoAttributes()-1, tidAttr->Copy()); auxRelation->AppendTuple(auxTuple); auxTuple->DeleteIfAllowed(); relation->UpdateTuple(tup,*changedIndices,*newAttrs); qp->SetModified(qp->GetSon(s, 1)); qp->SetModified(qp->GetSon(s, 2)); tup->DeleteIfAllowed(); delete changedIndices; delete newAttrs; result.setAddr(newTuple); return YIELD; } else return CANCEL; case CLOSE : qp->Close(args[0].addr); if(local.addr) { resultTupleType = (TupleType *)local.addr; resultTupleType->DeleteIfAllowed(); local.setAddr(0); } return 0; } return 0; } /* 2.30.3 Specification of operator ~updatedirectsave~ */ const string UpdateDirectSaveSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" " "\"Example\" ) " "( stream(tuple(x)) x rel(tuple(x)) x rel(tuple(x @ x @ [TID tid]))" " x [(a1, (tuple(x)" " -> d1)) ... (an, (tuple(x) -> dn))] -> " "stream(tuple(x @[x1_old t1]@ ...[xn_old tn] @ [TID tid]))" "" "_ _ _ updatedirectsave [funlist]" "Like updatedirect but saves the resulttuples" " to the auxiliary relation." "query ten feed ten tenU updatedirectsave [nr : " ".nr * 5] consume" "" ") )"; /* 2.30.4 Definition of operator ~updatedirectsave~ */ Operator extrelupdatedirectsave ( "updatedirectsave", // name UpdateDirectSaveSpec, // specification UpdateDirectSave, // value mapping Operator::SimpleSelect, // trivial selection function updateDirectSaveRelTypeMap // type mapping ); /* 2.31 Operator ~updatesearchsave~ Updates each tuple of the relation that has the same values as one of the input-tuples by replacing the attributevalues of the attributes given by their names in the function-argumentlist with the new values received from the functions. The updated tuple is made persistent and as the resultstream tuples are returned that contain the new values in first places, then all old values and finally the TupleIdentifier of the updated tuple. Additionally the resulttuples are stored in an auxiliary relation given as the third argument 2.31.1 Type mapping function of operator ~updatesearchsave~ */ ListExpr updateSearchSaveRelTypeMap(ListExpr args) { return updateSaveTypeMap(args, "updatesearchsave"); } /* 2.31.2 Value mapping function of operator ~updatesearchsave~ */ int UpdateSearchSave(Word* args, Word& result, int message, Word& local, Supplier s) { Word t, value, elem; t.addr = 0; value.addr = 0; elem.addr = 0; Tuple* tup = 0; Tuple* newTuple = 0; Tuple* nextTup = 0; Supplier supplier, supplier2, supplier3, son; int noOfAttrs = 0, index = 0; ArgVectorPointer funargs; ListExpr resultType = nl->Empty(); GenericRelation* relation = 0; Relation* auxRelation = 0; GenericRelationIterator* iter = 0; Attribute* newAttribute = 0; typedef vector Bucket; Bucket* nextBucket = 0; struct LocalTransport { LocalTransport(size_t bucks = 997 ): buckets(bucks), updatedTuples( new Bucket() ), hashTable( new vector(buckets) ), resultTupleType( 0 ) { vector::iterator i = hashTable->begin(); for (; i != hashTable->end(); i++) { *i = new Bucket(); } } ~LocalTransport() { for( Bucket::iterator i = updatedTuples->begin(); i != updatedTuples->end(); i++ ) { (*i)->DeleteIfAllowed(); } delete updatedTuples; vector::iterator i = hashTable->begin(); for (; i != hashTable->end(); i++) { for( Bucket::iterator j = (*i)->begin(); j != (*i)->end(); j++ ) { (*j)->DeleteIfAllowed(); } delete (*i); } delete hashTable; resultTupleType->DeleteIfAllowed(); } inline Bucket* getBucket(size_t hashvalue) { return (*hashTable)[hashvalue % buckets]; } inline void newUpdate(Tuple* t) { t->IncReference(); updatedTuples->push_back(t); } inline Tuple* lastUpdate() { if ( updatedTuples->empty() ) { return 0; } Tuple* t = updatedTuples->back(); t->DeleteIfAllowed(); updatedTuples->pop_back(); return t; } private: size_t buckets; public: Bucket* updatedTuples; vector* hashTable; TupleType* resultTupleType; }; LocalTransport* localTransport; size_t hashValue ; bool tupleFound; switch (message) { case OPEN : localTransport = new LocalTransport(); qp->Open(args[0].addr); relation = (GenericRelation*)(args[1].addr); assert(relation != 0); // fill hashtable iter = relation->MakeScan(); nextTup = iter->GetNextTuple(); while (nextTup) { hashValue = 0; for( int i = 0; i < nextTup->GetNoAttributes(); i++ ) hashValue += ((Attribute*) (nextTup->GetAttribute(i)))->HashValue(); nextBucket = localTransport->getBucket(hashValue); nextBucket->push_back(nextTup); nextTup = iter->GetNextTuple(); } delete iter; resultType = GetTupleResultType( s ); localTransport->resultTupleType = new TupleType( nl->Second( resultType ) ); local.setAddr( localTransport ); return 0; case REQUEST : { localTransport = (LocalTransport*) local.addr; // Check if an already updated duplicate of the last // input tuples has to be sent to the outputstream first Tuple* lt = localTransport->lastUpdate(); if ( lt != 0 ) { result.setAddr(lt); return YIELD; } // No more duplicates to be sent to the outputstream relation = (GenericRelation*) args[1].addr; auxRelation = (Relation*)(args[2].addr); assert(auxRelation != 0); // tupleFound will stay false until a tuple with the same // values as one of the input tuples was found tupleFound = false; while ( !tupleFound ) { qp->Request(args[0].addr,t); if (qp->Received(args[0].addr)) { // process a tuple of the input stream tup = (Tuple*)t.addr; hashValue = 0; for( int i = 0; i < tup->GetNoAttributes(); i++ ) hashValue += ((Attribute*) (tup->GetAttribute(i)))->HashValue(); SortOrderSpecification full; for( int i = 0; i < tup->GetNoAttributes(); i++ ) full.push_back(pair (i+1,false)); TupleCompareBy compare(full); // look up the hash table for the correct bucket nextBucket = localTransport->getBucket(hashValue); // Look for all tuples in the bucket if they have the // same attribute values for (size_t j = 0; j < nextBucket->size(); j++) { nextTup = (*nextBucket)[j]; if (nextTup != 0) { if(!compare(nextTup,tup) && !compare(tup,nextTup)) { int nextTupAttrs = nextTup->GetNoAttributes(); newTuple = new Tuple( localTransport->resultTupleType ); assert( newTuple->GetNoAttributes() == 2 * nextTupAttrs + 1); for (int i = 0; i < nextTupAttrs; i++) { newTuple->CopyAttribute(i, nextTup , i); newTuple->CopyAttribute(i, nextTup , nextTupAttrs+i); } noOfAttrs = ((CcInt*)args[4].addr)->GetIntval(); // Supplier for the updatefunctions supplier = args[3].addr; vector* changedIndices = new vector(noOfAttrs); vector* newAttrs = new vector(noOfAttrs); for (int i=1; i <= noOfAttrs; i++) { // Supplier for the next attributeindex son = qp->GetSupplier(args[5].addr, i-1); qp->Request(son, elem); index = ((CcInt*)elem.addr)->GetIntval() -1; (*changedIndices)[i-1] = index; // Suppliers for the next updatefunctions supplier2 = qp->GetSupplier(supplier, i-1); supplier3 = qp->GetSupplier(supplier2, 1); funargs = qp->Argument(supplier3); ((*funargs)[0]).setAddr(nextTup); qp->Request(supplier3,value); newAttribute = ((Attribute*)value.addr)->Clone(); (*newAttrs)[i-1] = newAttribute; // change attribute value for the output tuple newTuple->PutAttribute(index, newAttribute); } nextTup->IncReference(); qp->SetModified(qp->GetSon(s, 1)); qp->SetModified(qp->GetSon(s, 2)); relation->UpdateTuple( nextTup,*changedIndices,*newAttrs); // add tid to newTuple const TupleId& tid = nextTup->GetTupleId(); Attribute* tidAttr = new TupleIdentifier(true,tid); newTuple->PutAttribute(newTuple->GetNoAttributes() - 1,tidAttr); // copy the updated tuple into auxTuple and append it // to the auxiliary relation Tuple *auxTuple = new Tuple( auxRelation->GetTupleType() ); for (int i = 0; i < auxTuple->GetNoAttributes()-1; i++) { auxTuple->CopyAttribute(i, newTuple, i); } auxTuple->PutAttribute( auxTuple->GetNoAttributes()-1, tidAttr->Copy() ); auxRelation->AppendTuple(auxTuple); auxTuple->DeleteIfAllowed(); delete changedIndices; delete newAttrs; localTransport->newUpdate(newTuple); } } } // Check if at least one updated tuple has to be send to // the outputstream Tuple* t = localTransport->lastUpdate(); if ( t != 0 ) { result.setAddr(t); tupleFound = true; } tup->DeleteIfAllowed(); } else { // if (qp->Received(args[0].addr)) return CANCEL; } }// while ( !tupleFound ); return YIELD; } // case REQUEST case CLOSE : qp->Close(args[0].addr); if(local.addr) { localTransport = (LocalTransport*) local.addr; delete localTransport; local.setAddr(0); } return 0; } return 0; } /* 2.31.3 Specification of operator ~updatesearchsave~ */ const string UpdateSearchSaveSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" " "\"Example\" ) " "( stream(tuple(x)) x rel(tuple(x)) x " "(rel(tuple(x @ x @ [TID tid]))) x [(a1, (tuple(x)" " -> d1)) ... (an, (tuple(x) -> dn))] -> " "stream(tuple(x @[x1_old t1]@...[xn_old t1] @ [TID tid]))" "" "_ _ _updatesearchsave [funlist]" "Like `updatesearch` but each result-tuple " " is appended to the auxiliary relation." "query staedteUp feed staedte staedteU " "updatesearchsave [Bev : .Bev +1000] consume" "" ") )"; /* 2.31.4 Definition of operator ~updatesearchsave~ */ Operator extrelupdatesearchsave ( "updatesearchsave", // name UpdateSearchSaveSpec, // specification UpdateSearchSave, // value mapping Operator::SimpleSelect, // trivial selection function updateSearchSaveRelTypeMap // type mapping ); /* 2.32 Operator ~addid~ 2.32.1 Type mapping function of operator ~addid~ ---- ((stream (tuple (x1 ... xn)))) -> (stream (tuple (x1 ... xn (TID tid)))) ---- */ ListExpr appendIdentifierTypeMap (ListExpr args) { if(!nl->HasLength(args,1)){ return listutils::typeError("one Argument expected"); } ListExpr arg = nl->First(args); if(!Stream::checkType(arg)){ return listutils::typeError("argument must be a stream of tuples"); } ListExpr attrList = nl->Second(nl->Second(arg)); ListExpr type; int index = listutils::findAttribute(attrList, "TID", type); if(index!=0){ return listutils::typeError("Attribute TID already " "present in tuple stream."); } ListExpr addList = nl->OneElemList(nl->TwoElemList( nl->SymbolAtom("TID"), listutils::basicSymbol())); return nl->TwoElemList( listutils::basicSymbol >(), nl->TwoElemList( listutils::basicSymbol(), listutils::concat(attrList, addList))); } /* 2.32.2 Value mapping function of operator ~addid~ */ int appendIdentifierValueMap(Word* args, Word& result, int message, Word& local, Supplier s) { Word t; Tuple* tup; TupleType *resultTupleType; ListExpr resultType; switch (message) { case OPEN : qp->Open(args[0].addr); resultType = GetTupleResultType( s ); resultTupleType = new TupleType( nl->Second( resultType ) ); local.setAddr( resultTupleType ); return 0; case REQUEST : resultTupleType = (TupleType*) local.addr; qp->Request(args[0].addr,t); if (qp->Received(args[0].addr)) { tup = (Tuple*)t.addr; Tuple *newTuple = new Tuple( resultTupleType ); for( int i = 0; i < tup->GetNoAttributes(); i++ ) newTuple->CopyAttribute( i, tup, i ); const TupleId& tid = tup->GetTupleId(); // cout << "TID: " << tid << endl; Attribute* tidAttr = new TupleIdentifier(true,tid); newTuple->PutAttribute( tup->GetNoAttributes(), tidAttr); result.setAddr(newTuple); tup->DeleteIfAllowed(); return YIELD; } else return CANCEL; case CLOSE : qp->Close(args[0].addr); if(local.addr) { resultTupleType = (TupleType*) local.addr; resultTupleType->DeleteIfAllowed(); local.setAddr(0); } return 0; } return 0; } /* 2.32.3 Specification of operator ~addid~ */ const string appendIdentifierSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" " "\"Example\" \"Comment\" \" \" \" \") " "( stream(tuple(x)) " " -> stream(tuple(x@[TID:tid]))] " "" "_ addid" "Appends an attribute which is the" " tuple-id of the tuple to each tuple." "query staedte feed addid consume" "" "Apply addid directly after a feed, because other " "operators my corrupt the tid " "(in-memory tuples all have tid=0)." ") )"; /* 2.32.4 Definition of operator ~addid~ */ Operator extreladdid ( "addid", // name appendIdentifierSpec, // specification appendIdentifierValueMap, // value mapping Operator::SimpleSelect, // trivial selection function appendIdentifierTypeMap // type mapping ); /* 2.33 Operator ~deletebyid~ 2.33.1 Type mapping function of operator ~deletebyid~ ---- ((rel (tuple (x1 ... xn)))) x (TID tid) -> (stream (tuple (x1 ... xn (TID tid)))) ---- */ ListExpr deleteByIdTypeMap(ListExpr args) { ListExpr first,second, rest, listn, lastlistn, outList; string argstr="",valueString; if(nl->ListLength(args)!=2){ return listutils::typeError("two arguments expected"); } first = nl->First(args); second = nl->Second(args); if(!listutils::isRelDescription(first)){ return listutils::typeError("first argument must be a relation"); } if(!listutils::isSymbol(second,TupleIdentifier::BasicType())){ return listutils::typeError("second argument must be a tid"); } // build resultlist rest = nl->Second(nl->Second(first)); listn = nl->OneElemList(nl->First(rest)); 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()))); outList = nl->TwoElemList( nl->SymbolAtom(Symbol::STREAM()), nl->TwoElemList( nl->SymbolAtom(Tuple::BasicType()), listn)); return outList; } /* 2.33.2 Value mapping function of operator ~deletebyid~ */ int deleteByIdValueMap(Word* args, Word& result, int message, Word& local, Supplier s) { Tuple* resultTuple; Tuple* deleteTuple; Relation* relation; TupleIdentifier* tid; TupleType *resultTupleType; ListExpr resultType; bool* firstcall; switch (message) { case OPEN : firstcall = new bool; *firstcall = true; local.setAddr( firstcall ); return 0; case REQUEST : firstcall = (bool*) local.addr; if (*firstcall) { *firstcall = false; resultType = GetTupleResultType( s ); relation = (Relation*)(args[0].addr); assert(relation != 0); tid = (TupleIdentifier*)(args[1].addr); if(tid->IsDefined()){ deleteTuple = relation->GetTuple(tid->GetTid(), true); } else { deleteTuple = 0; } if (deleteTuple == 0) { return CANCEL; } resultTupleType = new TupleType( nl->Second( resultType ) ); resultTuple = new Tuple( resultTupleType ); for (int i = 0; i < deleteTuple->GetNoAttributes(); i++) { resultTuple->PutAttribute( i, deleteTuple->GetAttribute(i)->Clone()); } relation->DeleteTuple(deleteTuple); qp->SetModified(qp->GetSon(s, 0)); resultTuple->PutAttribute( resultTuple->GetNoAttributes() -1, tid->Clone()); result.setAddr(resultTuple); resultTupleType->DeleteIfAllowed(); deleteTuple->DeleteIfAllowed(); return YIELD; } else return CANCEL; case CLOSE : if(local.addr) { firstcall = (bool*) local.addr; delete firstcall; local.setAddr(0); } return 0; } return 0; } /* 2.33.3 Specification of operator ~deletebyid~ */ const string deleteByIdSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" " "\"Example\" ) " "( rel(tuple(x))) x (tid) " " -> stream(tuple(x@[TID:tid]))] " "" " _ deletebyid _" "Deletes the tuple with the id from the" "second argument from the relaton." "query staedte deletebyid [[const tid value (5)]] count" "" ") )"; /* 2.33.4 Definition of operator ~deletebyid~ */ Operator extreldeletebyid ( "deletebyid", // name deleteByIdSpec, // specification deleteByIdValueMap, // value mapping Operator::SimpleSelect, // trivial selection function deleteByIdTypeMap // type mapping ); /* 2.34 Operator ~updatebyid~ 2.34.1 Type mapping function of operator ~updatebyid~ ---- ((rel (tuple (X)))) x (tid) x ((ai1 (map x xi1)) ... (aij (map x xij)))) -> (stream (tuple (X @ (a1_old x1) ... (an_old xn)(TID tid))))) where X = ((a1 x1) ... (an xn)) and ai1 - aij in (a1 .. an) ---- */ ListExpr updateByIdTypeMap(ListExpr args) { ListExpr first, second,third, rest, listn, lastlistn, first2, second2, firstr,attrType, numberList, lastNumberList,oldAttribute, outlist; first = second = third = rest = listn = lastlistn = first2 = second2 = firstr = attrType = numberList = lastNumberList = oldAttribute = outlist = nl->TheEmptyList(); string argstr,valueString, argstr2, argstr3, oldName; int attrIndex, noAttrs ; bool firstcall = true; if(nl->ListLength(args)!=3){ return listutils::typeError("three arguments expected"); } first = nl->First(args); second = nl->Second(args); third = nl->Third(args); // Check relationa if(!listutils::isRelDescription(first)){ return listutils::typeError("relation as first arg expected"); } // Check second argument if(!listutils::isSymbol(second,TupleIdentifier::BasicType())){ return listutils::typeError("second argument should be tid"); } if(nl->ListLength(third<1)){ return listutils::typeError("non-empty function list expected " "as third arg"); } rest = third; noAttrs = nl->ListLength(third); // Go through all functions while (!(nl->IsEmpty(rest))) { firstr = nl->First(rest); rest = nl->Rest(rest); first2 = nl->First(firstr); second2 = nl->Second(firstr); // Is it a function? nl->WriteToString(argstr, second2); if(!listutils::isMap<1>(second2)){ return listutils::typeError("invalid function definition found"); } if(!nl->Equal(nl->Second(first),nl->Second(second2))){ return listutils::typeError("argument of the function differs " "from the corresponding attribute"); } if(!listutils::isSymbol(first2)){ return listutils::typeError("invalid attribute name " + nl->ToString(first2)); } nl->WriteToString(argstr, first2); 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(second2))){ return listutils::typeError("attribute type and result type" " of the function differ"); } // Construct a list with all indices of the changed attributes // in the inputstream to be appended to the resultstream if (firstcall) { numberList = nl->OneElemList(nl->IntAtom(attrIndex)); lastNumberList = numberList; firstcall = false; } else { lastNumberList = nl->Append( lastNumberList, nl->IntAtom(attrIndex)); } } // build first part of the resultstream rest = nl->Second(nl->Second(first)); listn = nl->OneElemList(nl->First(rest)); lastlistn = listn; rest = nl->Rest(rest); while (!(nl->IsEmpty(rest))) { lastlistn = nl->Append(lastlistn,nl->First(rest)); rest = nl->Rest(rest); } // build second part of the resultstream rest = nl->Second(nl->Second(first)); 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); } lastlistn = nl->Append( lastlistn, nl->TwoElemList( nl->SymbolAtom("TID"), nl->SymbolAtom(TupleIdentifier::BasicType()))); outlist = nl->ThreeElemList( nl->SymbolAtom(Symbol::APPEND()), nl->TwoElemList( nl->IntAtom(noAttrs), numberList), nl->TwoElemList( nl->SymbolAtom(Symbol::STREAM()), nl->TwoElemList( nl->SymbolAtom(Tuple::BasicType()), listn))); return outlist; } /* 2.34.2 Value mapping function of operator ~updatebyid~ */ int updateByIdValueMap(Word* args, Word& result, int message, Word& local, Supplier s) { Word elem, value; Tuple* resultTuple; Tuple* updateTuple; Supplier supplier, supplier2, supplier3, son; Relation* relation; TupleIdentifier* tid; int noOfAttrs, index; ArgVectorPointer funargs; Attribute* newAttribute; TupleType *resultTupleType; ListExpr resultType; bool* firstcall; switch (message) { case OPEN : firstcall = new bool; *firstcall = true; local.setAddr( firstcall ); return 0; case REQUEST : firstcall = (bool*) local.addr; if (*firstcall) { *firstcall = false; relation = (Relation*)(args[0].addr); assert(relation != 0); tid = (TupleIdentifier*)(args[1].addr); updateTuple = tid->IsDefined()?relation->GetTuple(tid->GetTid(), true) : 0; if (updateTuple == 0) { return CANCEL; } resultType = GetTupleResultType( s ); resultTupleType = new TupleType( nl->Second( resultType ) ); resultTuple = new Tuple( resultTupleType ); for (int i = 0; i < updateTuple->GetNoAttributes(); i++) { resultTuple->PutAttribute( updateTuple->GetNoAttributes() +i, updateTuple->GetAttribute(i)->Clone()); } // Number of attributes to be replaced noOfAttrs = ((CcInt*)args[3].addr)->GetIntval(); // Supplier for the functions supplier = args[2].addr; vector* changedIndices = new vector(noOfAttrs); vector* newAttrs = new vector(noOfAttrs); for (int i=1; i <= noOfAttrs; i++) { // Get next appended index son = qp->GetSupplier(args[4].addr, i-1); qp->Request(son, elem); index = ((CcInt*)elem.addr)->GetIntval() -1; (*changedIndices)[i-1] = index; // Get next function definition supplier2 = qp->GetSupplier(supplier, i-1); // Get the function supplier3 = qp->GetSupplier(supplier2, 1); funargs = qp->Argument(supplier3); ((*funargs)[0]).setAddr(updateTuple); qp->Request(supplier3,value); newAttribute = ((Attribute*)value.addr)->Clone(); (*newAttrs)[i-1] = newAttribute; } relation->UpdateTuple(updateTuple,*changedIndices,*newAttrs); qp->SetModified(qp->GetSon(s, 0)); for (int i = 0; i < updateTuple->GetNoAttributes(); i++) resultTuple->CopyAttribute( i, updateTuple, i ); resultTuple->PutAttribute( resultTuple->GetNoAttributes() -1, tid->Clone()); result.setAddr(resultTuple); delete changedIndices; delete newAttrs; resultTupleType->DeleteIfAllowed(); updateTuple->DeleteIfAllowed(); return YIELD; } else return CANCEL; case CLOSE : if(local.addr) { firstcall = (bool*) local.addr; delete firstcall; local.setAddr(0); } return 0; } return 0; } /* 2.34.3 Specification of operator ~updatebyid~ */ const string updateByIdSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" " "\"Example\" ) " "(stream(tuple(x))) x (rel(tuple(x))) x " "(tid) x [(a1, (tuple(x)" " -> d1)) ... (an, (tuple(x) -> dn))] -> " "stream(tuple(x @[x1_old t1] @...[xn_old tn] @[TID tid])))" "" " _ _ updatebyid [ _; funlist ]" "Updateds the tuple with the id from the" "third argument by applying the functions of the " " list to the tuple." "query staedte feed staedte " "updatebyid [[const tid value (5)]" " (Bev: .Bev + 1000, PLZ: .PLZ - 50] count" "" ") )"; /* 2.34.4 Definition of operator ~updatebyid~ */ Operator extrelupdatebyid ( "updatebyid", // name updateByIdSpec, // specification updateByIdValueMap, // value mapping Operator::SimpleSelect, // trivial selection function updateByIdTypeMap // type mapping ); /* 7.3 Operator ~insertrtree~ For each tuple of the inputstream inserts an entry into the rtree. The entry is built from the spatial-attribute over which the tree is built and the tuple-identifier wich is extracted from the input-tuples as the last attribute. The inputstream is returned again as the result of this operator. 7.3.0 General Type mapping function of operators ~insertrtree~, ~deletertree~, and ~updatertree~ Type mapping ~insertrtree~ and ~deletertree~ on a rtree ---- (stream (tuple ((a1 x1) ... (an xn) (tid int)))) (rtree X ti) ai -> (stream (tuple ((a1 x1) ... (an xn) (TID tid)))) where X = (tuple ((a1 x1) ... (an xn))) ---- Type mapping ~updatertree~ on a rtree ---- (stream (tuple ((a1 x1) ... (an xn)(a1_old x1)... (an_old xn) (TID tid)))) (rtree X ti) ai -> (stream (tuple ((a1 x1) ... (an xn)(a1_old x1) (an_old xn) (TID tid)))) where X = (tuple ((a1 x1) ... (an xn))) ---- */ ListExpr allUpdatesRTreeTypeMap( ListExpr& args, string opName ) { ListExpr rest,next,listn,lastlistn,restRTreeAttrs, oldAttribute,outList; string argstr, argstr2, oldName; AlgebraManager* algMgr = SecondoSystem::GetAlgebraManager(); ListExpr errorInfo = nl->OneElemList( nl->SymbolAtom( "ERRORS" ) ); if(nl->ListLength(args)!=3){ return listutils::typeError("three arguments expected"); } /* Split argument in three parts */ ListExpr streamDescription = nl->First(args); ListExpr rtreeDescription = nl->Second(args); ListExpr nameOfKeyAttribute = nl->Third(args); if(!listutils::isTupleStream(streamDescription)){ return listutils::typeError("first argument is not a tuple stream"); } // Test if last attribute is of type 'tid' rest = nl->Second(nl->Second(streamDescription)); while (!(nl->IsEmpty(rest))) { next = nl->First(rest); rest = nl->Rest(rest); } if(!listutils::isSymbol(nl->Second(next),TupleIdentifier::BasicType())){ return listutils::typeError("last attribute in the tuple must be a tid"); } if(!listutils::isRTreeDescription(rtreeDescription)){ return listutils::typeError("second argument is not an rtree"); } // Test rtree ListExpr rtreeSymbol = nl->First(rtreeDescription);; ListExpr rtreeTupleDescription = nl->Second(rtreeDescription); ListExpr rtreeKeyType = nl->Third(rtreeDescription); ListExpr rtreeType = nl->Fourth(rtreeDescription); ListExpr rtreeAttrList = nl->Second(rtreeTupleDescription); /* handle rtree type constructor */ if(!listutils::isSymbol(rtreeSymbol,RTree2TID::BasicType()) && !listutils::isSymbol(rtreeSymbol,RTree3TID::BasicType())){ return listutils::typeError("rtree or rtree3 expected as third argument"); } if(!listutils::isDATA(rtreeKeyType)){ return listutils::typeError("the rtree does not index a relation"); } if( nl->BoolValue(rtreeType)){ return listutils::typeError("double indexing not supported"); } if(!listutils::isSymbol(nameOfKeyAttribute)){ return listutils::typeError("key attribute in rtree is not a valid name"); } // Check whether tupledescription of the stream without the last // attribute is the same as the tupledescription of the rtree rest = nl->Second(nl->Second(streamDescription)); if(nl->ListLength(rest)<2){ return listutils::typeError("at least two attributes" " required in tuple stream"); } //Test if stream-tupledescription fits to btree-tupledescription listn = nl->OneElemList(nl->First(rest)); lastlistn = listn; rest = nl->Rest(rest); // For updates the inputtuples need to carry the old // attributevalues after the new values but their names with // an additional _old at the end if (opName == "updatertree") { // Compare first part of the streamdescription while (nl->ListLength(rest) > nl->ListLength(rtreeAttrList) + 1) { lastlistn = nl->Append(lastlistn,nl->First(rest)); rest = nl->Rest(rest); } if(!nl->Equal(listn,rtreeAttrList)){ return listutils::typeError("tuple descriprions differ"); } // Compare second part of the streamdescription restRTreeAttrs = rtreeAttrList; while (nl->ListLength(rest) > 1) { nl->WriteToString(oldName, nl->First(nl->First(restRTreeAttrs))); oldName += "_old"; oldAttribute = nl->TwoElemList( nl->SymbolAtom(oldName), nl->Second(nl->First(restRTreeAttrs))); if(!nl->Equal(oldAttribute,nl->First(rest))){ return listutils::typeError( "Second part of the tupledescription of the stream " "without the last attribute has to be the same as the " "tupledescription of the rtree except for that" " the attributenames carry an additional '_old.'"); } rest = nl->Rest(rest); restRTreeAttrs = nl->Rest(restRTreeAttrs); } } // For insert and delete check whether tupledescription of the // stream without the last attribute is the same as the // tupledescription of the rtree else // operators insertrtree and deletertree { while (nl->ListLength(rest) > 1) { lastlistn = nl->Append(lastlistn,nl->First(rest)); rest = nl->Rest(rest); } if(!nl->Equal(listn,rtreeAttrList)){ return listutils::typeError( " tupledescription of the stream without the" "last attribute has to be the same as the " "tupledescription of the rtree"); } } // Test if attributename of the third argument exists as a name // in the attributlist of the streamtuples string attrname = nl->SymbolValue(nameOfKeyAttribute); ListExpr attrType; int j = listutils::findAttribute(listn,attrname,attrType); if(j==0){ return listutils::typeError("attribute " + attrname + " not known"); } //Test if type of the attriubte which shall be taken as a key is // the same as the keytype of the rtree if(!nl->Equal(attrType,rtreeKeyType)){ return listutils::typeError("attribute type in rtree and relation differ"); } // Check if indexed attribute has a spatial-type if( !listutils::isKind(attrType,Kind::SPATIAL2D()) && !listutils::isKind(attrType,Kind::SPATIAL3D()) && !listutils::isKind(attrType,Kind::SPATIAL4D()) && !listutils::isSymbol(attrType,Rectangle<2>::BasicType()) && !listutils::isSymbol(attrType,Rectangle<3>::BasicType()) && !listutils::isSymbol(attrType,Rectangle<4>::BasicType()) ){ return listutils::typeError("indexed type not supported" " (not in SPATIAL2D, SPATOIAL3D, SPATIAL4D," " rect, rect3, rect4}"); } // Extract dimension and spatianltype to append them to the // resultlist int dim = 0; int spatial = 0; if (nl->IsEqual(attrType, Rectangle<2>::BasicType())) dim = 2; if (nl->IsEqual(attrType, Rectangle<3>::BasicType())) dim = 3; if (nl->IsEqual(attrType, Rectangle<4>::BasicType())) dim = 4; if (algMgr->CheckKind(Kind::SPATIAL2D(), attrType, errorInfo)) { dim = 2; spatial = 1; } if (algMgr->CheckKind(Kind::SPATIAL3D(), attrType, errorInfo)) { dim = 3; spatial = 1; } if (algMgr->CheckKind(Kind::SPATIAL4D(), attrType, errorInfo)) { dim = 4; spatial = 1; } // Append the index of the attribute over which the btree is built // to the resultlist. ListExpr append = nl->OneElemList(nl->IntAtom(j)); ListExpr lastAppend = append; //Append the dimension of the spatial-attribute to the resutllist. lastAppend = nl->Append(lastAppend,nl->IntAtom(dim)); //Append if the index-attribute is of 'rect'- or 'spatial'-type lastAppend = nl->Append(lastAppend,nl->IntAtom(spatial)); //Append the index of the attribute over which the btree is built //to the resultlist. outList = nl->ThreeElemList( nl->SymbolAtom(Symbol::APPEND()), nl->OneElemList(append), streamDescription); return outList; } /* 7.3.1 TypeMapping of operator ~insertrtree~ */ ListExpr insertRTreeTypeMap(ListExpr args) { return allUpdatesRTreeTypeMap(args, "insertrtree"); } /* 7.3.2 ValueMapping of operator ~insertrtree~ */ template void insertRTree_rect(Word& rtreeWord, Attribute* keyAttr, TupleId& oldTid) { R_Tree *rtree = (R_Tree*)rtreeWord.addr; BBox *box = (BBox*)keyAttr; R_TreeLeafEntry e( *box, oldTid ); rtree->Insert( e ); } template void insertRTree_spatial(Word& rtreeWord, Attribute* keyAttr, TupleId& oldTid){ R_Tree *rtree = (R_Tree*)rtreeWord.addr; BBox box = ((StandardSpatialAttribute*)keyAttr)->BoundingBox(); R_TreeLeafEntry e( box, oldTid ); rtree->Insert( e ); } int insertRTreeValueMap(Word* args, Word& result, int message, Word& local, Supplier s) { Word t, attrPos, dimWord, spatialWord; Tuple* tup; CcInt* indexp; CcInt* dimp; CcInt* spatialp; int index, dim, spatial; Attribute* keyAttr; Attribute* tidAttr; TupleId oldTid; SmiKey key; int* localTransport; Supplier suppIndex, suppDim, suppSpatial; switch (message) { case OPEN : qp->Open(args[0].addr); suppIndex = qp->GetSupplier(args[3].addr,0); qp->Request(suppIndex,attrPos); indexp = ((CcInt*)attrPos.addr); suppDim = qp->GetSupplier(args[3].addr,1); qp->Request(suppDim,dimWord); dimp = ((CcInt*)dimWord.addr); suppSpatial = qp->GetSupplier(args[3].addr,2); qp->Request(suppSpatial,spatialWord); spatialp = ((CcInt*)spatialWord.addr); localTransport = new int[3]; localTransport[0] = indexp->GetIntval(); localTransport[1] = dimp->GetIntval(); localTransport[2] = spatialp->GetIntval(); local.setAddr(localTransport ); return 0; case REQUEST : localTransport = (int*) local.addr; index = localTransport[0]; dim = localTransport[1]; spatial = localTransport[2]; qp->Request(args[0].addr,t); if (qp->Received(args[0].addr)) { qp->SetModified(qp->GetSon(s, 1)); tup = (Tuple*)t.addr; keyAttr = tup->GetAttribute(index - 1); tidAttr = tup->GetAttribute(tup->GetNoAttributes() - 1); oldTid = ((TupleIdentifier*)tidAttr)->GetTid(); if (spatial) { switch(dim) { case 2: insertRTree_spatial<2>(args[1],keyAttr,oldTid); break; case 3: insertRTree_spatial<3>(args[1],keyAttr,oldTid); break; case 4: insertRTree_spatial<4>(args[1],keyAttr,oldTid); break; } } else { switch(dim) { case 2: insertRTree_rect<2>(args[1],keyAttr,oldTid); break; case 3: insertRTree_rect<3>(args[1],keyAttr,oldTid); break; case 4: insertRTree_rect<4>(args[1],keyAttr,oldTid); break; } } result.setAddr(tup); return YIELD; } else return CANCEL; case CLOSE : qp->Close(args[0].addr); if(local.addr) { localTransport = (int*) local.addr; delete[] localTransport; local.setAddr(0); } return 0; } return 0; } /* 7.3.3 Specification of operator ~insertrtree~ */ const string insertRTreeSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" " "\"Example\" ) " "( stream(tuple(x@[TID:tid])) x rtree(tuple(x) ti) x xi" " -> stream(tuple(x@[TID:tid]))] " "" "_ _ insertrtree [_]" "Inserts references to the tuples with TupleId 'TID' " "into the rtree." "query neueStaedte feed staedte insert staedte_Ort " " insertrtree [Ort] count " "" ") )"; /* 7.3.4 Definition of operator ~insertrtree~ */ Operator insertrtree ( "insertrtree", // name insertRTreeSpec, // specification insertRTreeValueMap, // value mapping Operator::SimpleSelect, // trivial selection function insertRTreeTypeMap // type mapping ); /* 7.4 Operator ~deletertree~ For each tuple of the inputstream removes an entry from the rtree. The entry is built from the spatial-attribute over which the tree is built and the tuple-identifier wich is extracted from the input-tuples as the last attribute. The inputstream is returned again as the result of this operator. 7.4.1 Type mapping function of operator ~deletertree~ */ ListExpr deleteRTreeTypeMap( ListExpr args ) { return allUpdatesRTreeTypeMap(args, "deletertree"); } /* 7.4.1 Value mapping function of operator ~deletertree~ */ template void deleteRTree_rect(Word& rtreeWord, Attribute* keyAttr, TupleId& oldTid) { R_Tree *rtree = (R_Tree*)rtreeWord.addr; BBox *box = (BBox*)keyAttr; R_TreeLeafEntry e( *box, oldTid ); rtree->Remove( e ); } template void deleteRTree_spatial(Word& rtreeWord, Attribute* keyAttr, TupleId& oldTid) { R_Tree *rtree = (R_Tree*)rtreeWord.addr; BBox box = ((StandardSpatialAttribute*)keyAttr)->BoundingBox(); R_TreeLeafEntry e( box, oldTid ); rtree->Remove( e ); } int deleteRTreeValueMap(Word* args, Word& result, int message, Word& local, Supplier s) { Word t, attrPos, dimWord, spatialWord; Tuple* tup; CcInt* indexp; CcInt* dimp; CcInt* spatialp; int index, dim, spatial; Attribute* keyAttr; Attribute* tidAttr; TupleId oldTid; SmiKey key; int* localTransport; Supplier suppIndex, suppDim, suppSpatial; switch (message) { case OPEN : qp->Open(args[0].addr); suppIndex = qp->GetSupplier(args[3].addr,0); qp->Request(suppIndex,attrPos); indexp = ((CcInt*)attrPos.addr); suppDim = qp->GetSupplier(args[3].addr,1); qp->Request(suppDim,dimWord); dimp = ((CcInt*)dimWord.addr); suppSpatial = qp->GetSupplier(args[3].addr,2); qp->Request(suppSpatial,spatialWord); spatialp = ((CcInt*)spatialWord.addr); localTransport = new int[3]; localTransport[0] = indexp->GetIntval(); localTransport[1] = dimp->GetIntval(); localTransport[2] = spatialp->GetIntval(); local.setAddr(localTransport ); return 0; case REQUEST : localTransport = (int*) local.addr; index = localTransport[0]; dim = localTransport[1]; spatial = localTransport[2]; qp->Request(args[0].addr,t); if (qp->Received(args[0].addr)) { qp->SetModified(qp->GetSon(s, 1)); tup = (Tuple*)t.addr; keyAttr = tup->GetAttribute(index - 1); tidAttr = tup->GetAttribute(tup->GetNoAttributes() - 1); oldTid = ((TupleIdentifier*)tidAttr)->GetTid(); if (spatial) { switch(dim) { case 2: deleteRTree_spatial<2>(args[1],keyAttr,oldTid); break; case 3: deleteRTree_spatial<3>(args[1],keyAttr,oldTid); break; case 4: deleteRTree_spatial<4>(args[1],keyAttr,oldTid); break; } } else { switch(dim) { case 2: deleteRTree_rect<2>(args[1],keyAttr,oldTid); break; case 3: deleteRTree_rect<3>(args[1],keyAttr,oldTid); break; case 4: deleteRTree_rect<4>(args[1],keyAttr,oldTid); break; } } result.setAddr(tup); return YIELD; } else return CANCEL; case CLOSE : qp->Close(args[0].addr); if(local.addr) { localTransport = (int*) local.addr; delete[] localTransport; local.setAddr(0); } return 0; } return 0; } /* 7.4.3 Specification of operator ~deletertree~ */ const string deleteRTreeSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" " "\"Example\" ) " "( stream(tuple(x@[TID: tid])) x rtree(tuple(x) ti) x xi)" " -> stream(tuple(x@[TID: tid]))] " "" "_ _ deletertree [_]" "Deletes references to the tuples with TupleId 'TID' " "from the rtree." "query staedte feed filter [.Name = 'Hagen'] " " staedte deletedirect staedte_Ort deletertree [Ort] count " "" ") )"; /* 7.4.4 Definition of operator ~deletertree~ */ Operator deletertree ( "deletertree", // name deleteRTreeSpec, // specification deleteRTreeValueMap, // value mapping Operator::SimpleSelect, // trivial selection function deleteRTreeTypeMap // type mapping ); /* 7.5 Operator ~updatertree~ For each tuple of the inputstream checks if the attribute over which the tree has been built has changed. If it has changed the old entry for this tuple is removed and a new one is inserted. The entry is built from the spatial-attribute over which the tree is built and the tuple-identifier wich is extracted from the input-tuples as the last attribute. The inputstream is returned again as the result of this operator. 7.5.1 Type mapping function of operator ~updatertree~ */ ListExpr updateRTreeTypeMap( ListExpr args ) { return allUpdatesRTreeTypeMap (args, "updatertree"); } /* 7.5.1 Value mapping function of operator ~updatertree~ */ int updateRTreeValueMap(Word* args, Word& result, int message, Word& local, Supplier s) { Word t, attrPos, dimWord, spatialWord; Tuple* tup; CcInt* indexp; CcInt* dimp; CcInt* spatialp; int index, dim, spatial; Attribute* keyAttr; Attribute* oldKeyAttr; Attribute* tidAttr; TupleId oldTid; SmiKey key; int* localTransport; Supplier suppIndex, suppDim, suppSpatial; switch (message) { case OPEN : qp->Open(args[0].addr); suppIndex = qp->GetSupplier(args[3].addr,0); qp->Request(suppIndex,attrPos); indexp = ((CcInt*)attrPos.addr); suppDim = qp->GetSupplier(args[3].addr,1); qp->Request(suppDim,dimWord); dimp = ((CcInt*)dimWord.addr); suppSpatial = qp->GetSupplier(args[3].addr,2); qp->Request(suppSpatial,spatialWord); spatialp = ((CcInt*)spatialWord.addr); localTransport = new int[3]; localTransport[0] = indexp->GetIntval(); localTransport[1] = dimp->GetIntval(); localTransport[2] = spatialp->GetIntval(); local.setAddr(localTransport ); return 0; case REQUEST : localTransport = (int*) local.addr; index = localTransport[0]; dim = localTransport[1]; spatial = localTransport[2]; qp->Request(args[0].addr,t); if (qp->Received(args[0].addr)) { qp->SetModified(qp->GetSon(s, 1)); tup = (Tuple*)t.addr; keyAttr = tup->GetAttribute(index - 1); int noOfAttrs = tup->GetNoAttributes(); int oldIndex = (noOfAttrs - 1)/2 + index -1; oldKeyAttr = tup->GetAttribute(oldIndex); tidAttr = tup->GetAttribute(tup->GetNoAttributes() - 1); oldTid = ((TupleIdentifier*)tidAttr)->GetTid(); if (spatial) { switch(dim) { case 2: if ((((StandardSpatialAttribute<2>*) keyAttr)-> BoundingBox()) != (((StandardSpatialAttribute<2>*) oldKeyAttr)-> BoundingBox())) { deleteRTree_spatial<2>(args[1],oldKeyAttr,oldTid); insertRTree_spatial<2>(args[1],keyAttr,oldTid); } break; case 3: if ((((StandardSpatialAttribute<3>*) keyAttr)-> BoundingBox()) != (((StandardSpatialAttribute<3>*) oldKeyAttr)-> BoundingBox())) { deleteRTree_spatial<3>(args[1],oldKeyAttr,oldTid); insertRTree_spatial<3>(args[1],keyAttr,oldTid); } break; case 4: if ((((StandardSpatialAttribute<4>*) keyAttr)-> BoundingBox()) != (((StandardSpatialAttribute<4>*) oldKeyAttr)-> BoundingBox())) { deleteRTree_spatial<4>(args[1],oldKeyAttr,oldTid); insertRTree_spatial<4>(args[1],keyAttr,oldTid); } break; } } else { switch(dim) { case 2: if (((Rectangle<2>*) keyAttr) != ((Rectangle<2>*) oldKeyAttr)) { deleteRTree_rect<2>(args[1],oldKeyAttr,oldTid); insertRTree_rect<2>(args[1],keyAttr,oldTid); } break; case 3: if (((Rectangle<3>*) keyAttr) != ((Rectangle<3>*) oldKeyAttr)) { deleteRTree_rect<3>(args[1],oldKeyAttr,oldTid); insertRTree_rect<3>(args[1],keyAttr,oldTid); } break; case 4: if (((Rectangle<4>*) keyAttr) != ((Rectangle<4>*) oldKeyAttr)) { deleteRTree_rect<4>(args[1],oldKeyAttr,oldTid); insertRTree_rect<4>(args[1],keyAttr,oldTid); } break; } } result.setAddr(tup); return YIELD; } else return CANCEL; case CLOSE : qp->Close(args[0].addr); if(local.addr) { localTransport = (int*) local.addr; delete[] localTransport; local.setAddr(0); } return 0; } return 0; } /* 7.5.3 Specification of operator ~updatertree~ */ const string updateRTreeSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" " "\"Example\" ) " "(stream(tuple(x@[(a1_old x1) ... (an_old xn) (TID: tid)])) " "x rtree(tuple(x) ti) x xi" " -> stream(tuple(x@[(a1_old x1) ... (an_old xn) (TID: tid)]))] " "" "_ _ updatertree [_]" "Updates references to the tuples with TupleId 'TID'" "in the rtree." "query staedte feed filter [.Name = 'Hagen'] " " staedte updatedirect [Ort : newRegion] staedte_Ort " "updatertree [Ort] count " "" ") )"; /* 7.5.4 Definition of operator ~updatertree~ */ Operator updatertree ( "updatertree", // name updateRTreeSpec, // specification updateRTreeValueMap, // value mapping Operator::SimpleSelect, // trivial selection function updateRTreeTypeMap // type mapping ); /* 7.6 Operator ~updatedirect2~ 7.6.1 Type Mapping */ ListExpr updatedirect2TM(ListExpr args){ string err = "stream(tuple(X)) x rel(tuple(Y)) x AttrName x funlist expected"; if(!nl->HasLength(args,4)){ return listutils::typeError(err + " (wrong number of args)"); } if(!Stream::checkType(nl->First(args))){ return listutils::typeError(err + " (first arg is not a tuple stream)"); } if(!Relation::checkType(nl->Second(args))){ return listutils::typeError(err + "(second arg is not a relation)"); } ListExpr tt2 = nl->Second(nl->Second(args)); if(nl->AtomType(nl->Third(args)) != SymbolType){ return listutils::typeError(err + "(third arg is not a valid attribute name)"); } string tidName = nl->SymbolValue(nl->Third(args)); ListExpr streamTuple = nl->Second(nl->First(args)); ListExpr streamAttrList = nl->Second(streamTuple); ListExpr type; int index = listutils::findAttribute(streamAttrList, tidName, type); if(!index){ return listutils::typeError("attribute " + tidName + " unknown in stream"); } if(!TupleIdentifier::checkType(type)){ return listutils::typeError("attribute " + tidName + " not of type tid"); } ListExpr appendList = nl->OneElemList(nl->IntAtom(index-1)); ListExpr last = appendList; ListExpr funlist = nl->Fourth(args); if(nl->AtomType(funlist) != NoAtom){ return listutils::typeError(err + "fourth arg is not a list of functions"); } ListExpr relTuple = nl->Second(nl->Second(args)); ListExpr relAttrList = nl->Second(relTuple); set names; while(!nl->IsEmpty(funlist)){ ListExpr fun = nl->First(funlist); funlist = nl->Rest(funlist); if(!nl->HasLength(fun,2)){ // ( fundef) return listutils::typeError("invalid function definition found"); } ListExpr funName = nl->First(fun); if(nl->AtomType(funName)!=SymbolType){ return listutils::typeError("invalid name for function result"); } string name = nl->SymbolValue(nl->First(fun)); if(names.find(name)!=names.end()){ return listutils::typeError("attr " + name + " set twice"); } names.insert(name); int rindex = listutils::findAttribute(relAttrList, name, type); if(rindex ==0){ return listutils::typeError("attribute " + name + " not in relation"); } last = nl->Append(last,nl->IntAtom(rindex -1)); ListExpr fundef = nl->Second(fun); if(!listutils::isMap<2>(fundef)){ return listutils::typeError("invalid function definition for " + name ); } // check function arguments and result if(!nl->Equal(nl->Second(fundef), streamTuple)){ return listutils::typeError("invalid argument type" " (1st arg) for function " + name); } if(!nl->Equal(nl->Third(fundef), relTuple)){ return listutils::typeError("invalid argument type (2nd arg) for " "function " + name); } if(!nl->Equal(nl->Fourth(fundef), type)){ return listutils::typeError("function result for " + name + " not equal to the type in relation"); } } return nl->ThreeElemList( nl->SymbolAtom(Symbols::APPEND()), appendList, nl->TwoElemList(listutils::basicSymbol >(),tt2)); } /* 7.6.2 LocalInfo */ class updatedirect2Info{ public: updatedirect2Info(Word _stream, Relation* _rel, int _tidPos, Supplier _funlist, vector& _attrPos): stream(_stream), rel(_rel), tidPos(_tidPos), funlist(_funlist), attrPos(_attrPos){ stream.open(); for(size_t i=0;iGetSupplier(funlist,i); Supplier s2 = qp->GetSupplier(s1,1); funs.push_back(s2); funargs.push_back(qp->Argument(s2)); } } ~updatedirect2Info(){ stream.close(); } Tuple* next(){ Tuple* tuple = stream.request(); while(tuple){ TupleIdentifier* Tid =(TupleIdentifier*) tuple->GetAttribute(tidPos); if(Tid->IsDefined()){ TupleId tid = Tid->GetTid(); if(tid!=0){ Tuple* relTuple = rel->GetTuple(tid, true); if(relTuple){ vector changes = getChanges(tuple, relTuple); rel->UpdateTuple(relTuple, attrPos, changes); tuple->DeleteIfAllowed(); return relTuple; } } } tuple->DeleteIfAllowed(); tuple = stream.request(); } return 0; } private: Stream stream; Relation* rel; int tidPos; Supplier funlist; vector attrPos; vector funs; vector funargs; vector getChanges(Tuple* streamTuple, Tuple* relTuple){ vector res; for(size_t i=0;iRequest(funs[i],funres); res.push_back(((Attribute*)funres.addr)->Clone()); } return res; } }; /* 7.6.3 Value Mapping */ int updatedirect2VM(Word* args, Word& result, int message, Word& local, Supplier s) { updatedirect2Info* li = (updatedirect2Info*) local.addr; switch(message){ case OPEN : { if(li){ delete li; } Relation* rel = (Relation*) args[1].addr; int tidPos = ((CcInt*) args[4].addr)->GetValue(); Supplier funlist = qp->GetSon(s,3); vector repPos; for(int i=5; i< qp->GetNoSons(s); i++){ repPos.push_back(((CcInt*) args[i].addr)->GetValue()); } assert(repPos.size() == (size_t) qp->GetNoSons(funlist)); local.addr = new updatedirect2Info(args[0], rel, tidPos, funlist, repPos); return 0; } case REQUEST: result.addr = li?li->next():0; return result.addr?YIELD:CANCEL; case CLOSE: if(li){ qp->SetModified(qp->GetSon(s, 1)); // mark relation to be updated delete li; local.addr =0; } return 0; } return -1; } /* 7.6.4 Specification */ OperatorSpec updatedirect2Spec( " stream(tuple(X)) x rel(tuple(Y)) x attr x funlist -> stream(tuple(X))", "_ _ updatedirect2[ _ ; funlist ] ", "Updates tuples in a relation. The tupleid comes from the first argument" " and is specified by the attr argument. Each tuple is replaced by the " "same tuple but with replaced attributes according to the functions. " "The function may use parts from the stream (dot notation) or from the " "tuple stored in the relation (double dot notation).", "query ten1 feed addid ten1 [TID, No : .No + ..No * 2] count" ); /* 7.6.5 Operator instance */ Operator updatedirect2Op( "updatedirect2", updatedirect2Spec.getStr(), updatedirect2VM, Operator::SimpleSelect, updatedirect2TM ); ListExpr updatebyid2TM(ListExpr args){ if(!nl->HasLength(args,4)){ return listutils::typeError("wrong number of args"); } if(!Stream::checkType(nl->First(args))){ return listutils::typeError("first arg must be a tuple stream"); } if(!Relation::checkType(nl->Second(args))){ return listutils::typeError("second arg must be a relation"); } if(!listutils::isSymbol(nl->Third(args))){ return listutils::typeError("third arg is not a valid attribute name"); } ListExpr streamTuple = nl->Second(nl->First(args)); ListExpr streamAttrList = nl->Second(streamTuple); string attrName = nl->SymbolValue(nl->Third(args)); ListExpr attrType; int index = listutils::findAttribute(streamAttrList, attrName, attrType); if(!index){ return listutils::typeError("Attribute " + attrName + " not in " "tuple stream"); } if(!TupleIdentifier::checkType(attrType)){ return listutils::typeError("Attribute " + attrName + " is " "not of type tid"); } ListExpr appendList = nl->OneElemList(nl->IntAtom(index-1)); ListExpr last = appendList; ListExpr funList = nl->Fourth(args); ListExpr relTuple = nl->Second(nl->Second(args)); ListExpr relAttrList = nl->Second(relTuple); set names; while(!nl->IsEmpty(funList)){ ListExpr fun = nl->First(funList); funList = nl->Rest(funList); if(!nl->HasLength(fun, 2)){ // ( fundef) return listutils::typeError("invalid function definition found"); } ListExpr funName = nl->First(fun); if(nl->AtomType(funName)!=SymbolType){ return listutils::typeError("invalid name for function"); } string name = nl->SymbolValue(nl->First(fun)); if(names.find(name)!=names.end()){ return listutils::typeError("attr " + name + " set twice"); } names.insert(name); int rindex = listutils::findAttribute(relAttrList, name, attrType); if(rindex ==0){ return listutils::typeError("attribute " + name + " not in relation"); } last = nl->Append(last,nl->IntAtom(rindex -1)); ListExpr fundef = nl->Second(fun); if(!listutils::isMap<2>(fundef)){ return listutils::typeError("invalid function definition for " + name ); } // check function arguments and result if(!nl->Equal(nl->Second(fundef), streamTuple)){ return listutils::typeError("invalid argument type" " (1st arg) for function " + name); } if(!nl->Equal(nl->Third(fundef), relTuple)){ return listutils::typeError("invalid argument type (2nd arg) for " "function " + name); } if(!nl->Equal(nl->Fourth(fundef), attrType)){ return listutils::typeError("function result for " + name + " not equal to the type in relation"); } } //build type of the resultstream string oldName; ListExpr oldAttribute; ListExpr resAttrList = nl->Second(relTuple); ListExpr rest = nl->Second(relTuple); while(!nl->IsEmpty(rest)){ nl->WriteToString(oldName, nl->First(nl->First(rest))); oldName += "_old"; oldAttribute = nl->OneElemList(nl->TwoElemList( nl->SymbolAtom(oldName), nl->Second(nl->First(rest)))); resAttrList = listutils::concat(resAttrList, oldAttribute); rest = nl->Rest(rest); } resAttrList = listutils::concat( resAttrList, nl->OneElemList(nl->TwoElemList( nl->SymbolAtom("TID"), nl->SymbolAtom(TupleIdentifier::BasicType())))); return nl->ThreeElemList( nl->SymbolAtom(Symbols::APPEND()), appendList, nl->TwoElemList( listutils::basicSymbol >(), nl->TwoElemList( listutils::basicSymbol(), resAttrList))); } class updatebyid2Info{ public: updatebyid2Info(Word _stream, Relation* _rel, int _tidPos, Supplier _funlist, vector& _attrPos, ListExpr _tt): stream(_stream), rel(_rel), tidPos(_tidPos), funlist(_funlist), attrPos(_attrPos){ stream.open(); for(size_t i=0; iGetSupplier(funlist, i); Supplier s2 = qp->GetSupplier(s1, 1); funs.push_back(s2); funargs.push_back(qp->Argument(s2)); } tt = new TupleType(_tt); } ~updatebyid2Info(){ stream.close(); tt->DeleteIfAllowed(); } Tuple* next(){ Tuple* inTuple = stream.request(); while(inTuple){ TupleIdentifier* tid =(TupleIdentifier*) inTuple->GetAttribute(tidPos); if(tid->IsDefined()){ Tuple* relTuple = rel->GetTuple(tid->GetTid(), true); if(relTuple){ Tuple* outTuple = new Tuple(tt); int offset = relTuple->GetNoAttributes(); for(int i = 0; i < relTuple->GetNoAttributes(); i++){ outTuple->CopyAttribute(i, relTuple,i+offset); } vector changes = getChanges( inTuple, relTuple); rel->UpdateTuple(relTuple, attrPos, changes); for(int i = 0; i < relTuple->GetNoAttributes(); i++){ outTuple->CopyAttribute(i, relTuple, i); } Attribute* tidAttr = new TupleIdentifier (true,tid->GetTid()); outTuple->PutAttribute(offset*2 , tidAttr); inTuple->DeleteIfAllowed(); relTuple->DeleteIfAllowed(); return outTuple; } } inTuple->DeleteIfAllowed(); inTuple = stream.request(); } return 0; } private: Stream stream; Relation* rel; int tidPos; Supplier funlist; vector attrPos; TupleType* tt; vector funs; vector funargs; vector getChanges(Tuple* streamTuple, Tuple* relTuple){ vector res; for(size_t i=0;iRequest(funs[i],funres); res.push_back(((Attribute*)funres.addr)->Clone()); } return res; } }; int updatebyid2VM(Word* args, Word& result, int message, Word& local, Supplier s) { updatebyid2Info* li = (updatebyid2Info*) local.addr; switch(message){ case OPEN : { if(li){ delete li; } Relation* rel = (Relation*) args[1].addr; int tidPos = ((CcInt*) args[4].addr)->GetValue(); Supplier funlist = qp->GetSon(s,3); vector repPos; for(int i=5; i< qp->GetNoSons(s); i++){ repPos.push_back(((CcInt*) args[i].addr)->GetValue()); } assert(repPos.size() == (size_t) qp->GetNoSons(funlist)); ListExpr resTupleType = nl->Second(GetTupleResultType(s)); local.addr = new updatebyid2Info(args[0], rel, tidPos, funlist, repPos, resTupleType); return 0; } case REQUEST: result.addr = li?li->next():0; return result.addr?YIELD:CANCEL; case CLOSE: if(li){ qp->SetModified(qp->GetSon(s, 1)); // mark relation to be updated delete li; local.addr =0; } return 0; } return -1; } OperatorSpec updatebyid2Spec( "stream(tuple(X)) x rel(tuple(Y)) x attr x funlist -> " "stream(rel(tuple(Y@[Y1_old t1]@...[Yn_old tn]@[TID:tid])))", "_ _ updatebyid2[ _ ; funlist ] ", "Updates tuples in a relation. The tupleid comes from the first argument" " and is specified by the attr argument. Each tuple is replaced by the " "same tuple but with replaced attributes according to the functions. " "The function may use parts from the stream (dot notation) or from the " "tuple stored in the relation (double dot notation).", "query ten feed addid ten updatebyid2[TID, No : .No + ..No * 2] count" ); Operator updatebyid2Op( "updatebyid2", updatebyid2Spec.getStr(), updatebyid2VM, Operator::SimpleSelect, updatebyid2TM ); /* 7.7 deletebyId2 */ ListExpr deletebyid2TM(ListExpr args){ if(!nl->HasLength(args,3)){ return listutils::typeError("three arguments expected"); } if(!Stream::checkType(nl->First(args))){ return listutils::typeError("first arg must be a tuple stream"); } if(!Relation::checkType(nl->Second(args))){ return listutils::typeError("Second arg mut be a relation"); } if(!listutils::isSymbol(nl->Third(args))){ return listutils::typeError("third arg is not a valid attribute name"); } ListExpr attrList = nl->Second(nl->Second(nl->First(args))); string name = nl->SymbolValue(nl->Third(args)); ListExpr attrType; int index = listutils::findAttribute(attrList,name,attrType); if(!index){ return listutils::typeError("Attribute " + name + " not present in " "tuple stream"); } if(!TupleIdentifier::checkType(attrType)){ return listutils::typeError("Attribute " + name + " is not a tuple id"); } ListExpr resAttrList = listutils::concat(attrList, nl->Second(nl->Second(nl->Second(args)))); if(!listutils::isAttrList(resAttrList)){ return listutils::typeError("name conflicts between tuple stream " "and relation"); } return nl->ThreeElemList( nl->SymbolAtom(Symbols::APPEND()), nl->OneElemList( nl->IntAtom(index-1)), nl->TwoElemList( listutils::basicSymbol >(), nl->TwoElemList( listutils::basicSymbol(), resAttrList))); } class deletebyid2Info{ public: deletebyid2Info(Word _stream, Relation* _rel, int _idPos, ListExpr _tt): stream(_stream), rel(_rel), idPos(_idPos){ stream.open(); tt = new TupleType(_tt); } ~deletebyid2Info(){ stream.close(); tt->DeleteIfAllowed(); } Tuple* next(){ while(true){ Tuple* inTuple = stream.request(); if(!inTuple){ return 0; } TupleIdentifier* tid = (TupleIdentifier*)inTuple->GetAttribute(idPos); if(!tid->IsDefined()){ inTuple->DeleteIfAllowed(); } else { Tuple* delTuple = rel->GetTuple(tid->GetTid(),true); if(!delTuple){ inTuple->DeleteIfAllowed(); } else { rel->DeleteTuple(delTuple); return createOutTuple(inTuple,delTuple); } } } } private: Stream stream; Relation* rel; int idPos; TupleType* tt; Tuple* createOutTuple(Tuple* t1, Tuple* t2){ Tuple* resTuple = new Tuple(tt); for(int i=0;iGetNoAttributes();i++){ resTuple->CopyAttribute(i,t1,i); } int offset = t1->GetNoAttributes(); for(int i=0;iGetNoAttributes(); i++){ resTuple->CopyAttribute(i, t2,i+offset); } t1->DeleteIfAllowed(); t2->DeleteIfAllowed(); return resTuple; } }; int deletebyid2VM(Word* args, Word& result, int message, Word& local, Supplier s) { deletebyid2Info* li = (deletebyid2Info*) local.addr; switch(message){ case OPEN : if(li) delete li; local.addr = new deletebyid2Info(args[0], (Relation*) args[1].addr, ((CcInt*)args[3].addr)->GetValue(), 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; qp->SetModified(qp->GetSon(s, 1)); } return 0; } return -1; } OperatorSpec deletebyid2Spec( "stream(tuple(X)) x rel(tuple(Y)) x attrName -> stream(tuple(X@Y))", "_ _ deletebyid2[_]", "Deletes all tuples from a relation (2nd arg) " " specified by tuple ids in a tuple stream (first arg)" " referenced by an attribute name (3rd arg)", " query ten feed head[3] addid project[TID] ten deletebyid2 consume" ); Operator deletebyid2Op( "deletebyid2", deletebyid2Spec.getStr(), deletebyid2VM, Operator::SimpleSelect, deletebyid2TM ); /* delete by id 3 */ ListExpr deletebyid3TM(ListExpr args){ if(!nl->HasLength(args,2)){ return listutils::typeError("two args expected"); } if(!Stream::checkType(nl->First(args))){ return listutils::typeError("First arg must be a stream of tid"); } if(!Relation::checkType(nl->Second(args))){ return listutils::typeError("Second arg mut be a relation"); } return nl->TwoElemList( listutils::basicSymbol >(), nl->Second(nl->Second(args))); } class deletebyid3Info{ public: deletebyid3Info(Word _stream, Relation* _rel): stream(_stream), rel(_rel){ stream.open(); } ~deletebyid3Info(){ stream.close(); } Tuple* next(){ while(true){ TupleIdentifier* tid = stream.request(); if(!tid){ return 0; } if(!tid->IsDefined()){ tid->DeleteIfAllowed(); } else { Tuple* delTuple = rel->GetTuple(tid->GetTid(),true); tid->DeleteIfAllowed(); if(delTuple){ rel->DeleteTuple(delTuple); return delTuple; } } } } private: Stream stream; Relation* rel; }; int deletebyid3VM(Word* args, Word& result, int message, Word& local, Supplier s) { deletebyid3Info* li = (deletebyid3Info*) local.addr; switch(message){ case OPEN: if(li) delete li; local.addr = new deletebyid3Info(args[0], (Relation*) args[1].addr); return 0; case REQUEST: result.addr = li->next(); return result.addr?YIELD:CANCEL; case CLOSE: if(li){ delete li; local.addr = 0; qp->SetModified(qp->GetSon(s, 1)); } return 0; } return -1; } OperatorSpec deletebyid3Spec( "stream(tid) x rel(T) -> stream(T)", " _ _ deletebyid3", "Removes the tuples with given ids from a relation " "and feeds the removed tuples into a stream.", "query ten feed head[3] ids ten deletebyid3 consume" ); Operator deletebyid3Op( "deletebyid3", deletebyid3Spec.getStr(), deletebyid3VM, Operator::SimpleSelect, deletebyid3TM ); /* deletebyid 4 */ ListExpr deletebyid4TM(ListExpr args){ if(!nl->HasLength(args,3)){ return listutils::typeError("three arguments expected"); } if(!Stream::checkType(nl->First(args))){ return listutils::typeError("first arg must be a tuple stream"); } if(!Relation::checkType(nl->Second(args))){ return listutils::typeError("second arg must be a relation"); } if(!listutils::isSymbol(nl->Third(args))){ return listutils::typeError("third arg is not a valid attribute name"); } ListExpr attrList = nl->Second(nl->Second(nl->First(args))); string attrName = nl->SymbolValue(nl->Third(args)); ListExpr attrType; int index = listutils::findAttribute(attrList, attrName, attrType); if(!index){ return listutils::typeError("Attribute " + attrName + " not in " "tuple stream"); } if(!TupleIdentifier::checkType(attrType)){ return listutils::typeError("Attribute " + attrName + " is " "not a tuple identifier"); } ListExpr resAttrList = listutils::concat( nl->Second(nl->Second(nl->Second(args))), nl->OneElemList(nl->TwoElemList( nl->SymbolAtom("TID"), nl->SymbolAtom(TupleIdentifier::BasicType())))); cout << "resAttrList: " << nl->ToString(resAttrList) << endl; if(!listutils::isAttrList(resAttrList)){ return listutils::typeError("result attribute list is not valid"); } return nl->ThreeElemList( nl->SymbolAtom(Symbols::APPEND()), nl->OneElemList( nl->IntAtom(index-1)), nl->TwoElemList( listutils::basicSymbol >(), nl->TwoElemList( listutils::basicSymbol(), resAttrList))); } class deletebyid4Info{ public: deletebyid4Info(Word _stream, Relation* _rel, int _idPos, ListExpr _tt): stream(_stream), rel(_rel), idPos(_idPos){ stream.open(); tt = new TupleType(_tt); } ~deletebyid4Info(){ stream.close(); tt->DeleteIfAllowed(); } Tuple* next(){ while(true){ Tuple* inTuple = stream.request(); if(!inTuple){ return 0; } TupleIdentifier* tid = (TupleIdentifier*) inTuple->GetAttribute(idPos); if(tid->IsDefined()){ TupleId id = tid->GetTid(); Tuple* delTuple = rel->GetTuple(id, true); if(delTuple){ rel->DeleteTuple(delTuple); inTuple->DeleteIfAllowed(); return createOutTuple(delTuple, id); } } inTuple->DeleteIfAllowed(); } } private: Stream stream; Relation* rel; int idPos; TupleType* tt; Tuple* createOutTuple(Tuple* t, TupleId tid){ Tuple* resTuple = new Tuple(tt); for(int i = 0; i < t->GetNoAttributes(); i++){ resTuple->CopyAttribute(i,t,i); } //const TupleId& tid = t->GetTupleId(); Attribute* tidAttr = new TupleIdentifier(true,tid); resTuple->PutAttribute(t->GetNoAttributes(), tidAttr); t->DeleteIfAllowed(); return resTuple; } }; int deletebyid4VM(Word* args, Word& result, int message, Word& local, Supplier s){ deletebyid4Info* li = (deletebyid4Info*) local.addr; switch(message){ case OPEN : if(li) delete li; local.addr = new deletebyid4Info(args[0], (Relation*) args[1].addr, ((CcInt*) args[3].addr)->GetValue(), 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; qp->SetModified(qp->GetSon(s, 1)); } return 0; } return -1; } OperatorSpec deletebyid4Spec( "stream(tuple(X)) x rel(tuple(Y)) x attrName -> stream(tuple(Y@[TID:tid]))", "_ _ deletebyid4[_]", "Deletes all tuples from a relation (2nd arg) " " specified by tuple ids in a tuple stream (first arg)" " referenced by an attribute name (3rd arg)", " query ten feed head[3] addid ten deletebyid4 [TID] consume" ); Operator deletebyid4Op( "deletebyid4", deletebyid4Spec.getStr(), deletebyid4VM, Operator::SimpleSelect, deletebyid4TM ); /* Operator ~filterinsert~ */ ListExpr filterinsertTM(ListExpr args){ if(!nl->HasLength(args,3)){ return listutils::typeError("two arguments expected"); } ListExpr stream = nl->First(args); if(!Stream::checkType(stream)){ return listutils::typeError("first arg is not a tuple stream"); } ListExpr fun = nl->Second(args); if(!listutils::isMap<1>(fun)){ return listutils::typeError("second arg is not an unary function"); } if(!CcBool::checkType(nl->Third(fun))){ return listutils::typeError("function result is not a bool"); } if(!nl->Equal(nl->Second(stream), nl->Second(fun))){ return listutils::typeError("function arg and tuple type in " "stream differ"); } ListExpr rel = nl->Third(args); if(! ( Relation::checkType(rel) || OrderedRelation::checkType(rel))){ return listutils::typeError("third arg is not an (ordered) relation"); } if(!nl->Equal(nl->Second(stream), nl->Second(rel))){ return listutils::typeError("tuple type in stream and rel differ"); } return nl->First(args); } class filterinsertInfo{ public: filterinsertInfo(Word& _stream, Word& _fun, GenericRelation* _rel): stream(_stream), fun(_fun.addr), rel(_rel){ stream.open(); arg = qp->Argument(fun); } ~filterinsertInfo(){ stream.close(); } Tuple* next(){ Tuple* t; while( (t=stream.request())){ (*arg)[0] = t; qp->Request(fun,funresult); CcBool* r = (CcBool*) funresult.addr; bool k = r->IsDefined()?r->GetValue():false; if(k){ return t; } else { rel->AppendTuple(t); t->DeleteIfAllowed(); } } return 0; } private: Stream stream; Supplier fun; GenericRelation* rel; ArgVectorPointer arg; Word funresult; }; int filterinsertVM(Word* args, Word& result, int message, Word& local, Supplier s) { filterinsertInfo* li = (filterinsertInfo*) local.addr; switch(message){ case OPEN: if(li) delete li; local.addr = new filterinsertInfo(args[0],args[1], (GenericRelation*) args[2].addr); return 0; case REQUEST: result.addr = li?li->next():0; return result.addr?YIELD:CANCEL; case CLOSE: if(li){ delete li; local.addr = 0; qp->SetModified(qp->GetSon(s, 2)); } return 0; } return -1; } OperatorSpec filterinsertSpec( "stream(t) x (t->bool) x rel(t) -> stream(t)", "_ filterinsert[_,_]", "As the usual filter operator, this operator filters " "out tuples from a stream using a boolean function. " "The removed tuples are " "inserted into a relation.", "query ten feed filterinsert[.No > 3, t2] count" ); Operator filterinsertOp( "filterinsert", filterinsertSpec.getStr(), filterinsertVM, Operator::SimpleSelect, filterinsertTM ); /* 3 Class ~UpdateRelationAlgebra~ A new subclass ~UpdateRelationAlgebra~ of class ~Algebra~ is declared. The only specialization with respect to class ~Algebra~ takes place within the constructor: all type constructors and operators are registered at the actual algebra. After declaring the new class, its only instance ~extendedRelationAlgebra~ is defined. */ class UpdateRelationAlgebra : public Algebra { public: UpdateRelationAlgebra() : Algebra() { AddOperator(&extrelcreateinsertrel); AddOperator(&extrelcreatedeleterel); AddOperator(&extrelcreateupdaterel); AddOperator(&extrelinsert); AddOperator(&extrelinsert2); AddOperator(&extrelinsert3); AddOperator(&extrelinsertsave); AddOperator(&extrelinserttuple); AddOperator(&extrelinserttuplesave); AddOperator(&extreldeletesearch); AddOperator(&extreldeletedirect); AddOperator(&extreldeletesearchsave); AddOperator(&extreldeletedirectsave); AddOperator(&extrelupdatesearch); AddOperator(&extrelupdatedirect); AddOperator(&extrelupdatesearchsave); AddOperator(&extrelupdatedirectsave); AddOperator(&extreladdid); AddOperator(&extreldeletebyid); AddOperator(&extrelupdatebyid); AddOperator( &insertrtree ); AddOperator( &deletertree ); AddOperator( &updatertree ); AddOperator( &updatedirect2Op); AddOperator( &updatebyid2Op); AddOperator(&deletebyid2Op); AddOperator(&deletebyid3Op); AddOperator(&deletebyid4Op); AddOperator(&filterinsertOp); } ~UpdateRelationAlgebra() {}; }; /* 4 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. */ extern "C" Algebra* InitializeUpdateRelationAlgebra( NestedList* nlRef, QueryProcessor* qpRef ) { nl = nlRef; qp = qpRef; return (new UpdateRelationAlgebra()); }