/* ---- This file is part of SECONDO. Copyright (C) 2014, Faculty of Mathematics and Computer Science, Database Systems for New Applications. SECONDO is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. SECONDO is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with SECONDO; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ---- */ #include "Attribute.h" // implementation of attribute types #include "Algebra.h" // definition of the algebra #include "NestedList.h" // required at many places #include "QueryProcessor.h" // needed for implementing value mappings #include "AlgebraManager.h" // e.g., check for a certain kind #include "Operator.h" // for operator creation #include "StandardTypes.h" // priovides int, real, string, bool type #include "Algebras/FText/FTextAlgebra.h" #include "Symbols.h" // predefined strings #include "ListUtils.h" // useful functions for nested lists #include "Stream.h" // wrapper for secondo streams #include "LogMsg.h" // send error messages #include "Tools/Flob/DbArray.h" // use of DbArrays #include "Algebras/Relation-C++/RelationAlgebra.h" // use of tuples #include // required for some operators #include #include /* 0.5 Global Variables Secondo uses some variables designed as singleton pattern. For accessing these global variables, these variables have to be declared to be extern: */ extern NestedList *nl; extern QueryProcessor *qp; extern AlgebraManager *am; using namespace std; namespace tuplevector { class TupleVector{ public: TupleVector(int _maxSize): content(),maxSize(_maxSize) { if(maxSize <1) maxSize=1; content.reserve(maxSize); } TupleVector(const TupleVector& tv){ maxSize = tv.maxSize; for(size_t i=0;iIncReference(); content.push_back(t); } } ~TupleVector(){ for(Tuple*& tuple : content){ tuple->DeleteIfAllowed(); } } static const string BasicType(){ return "tuplevector"; } static bool checkType(ListExpr t){ if(!nl->HasLength(t,2)) return false; if(!nl->IsEqual(nl->First(t), BasicType())){ return false; } return listutils::isAttrList(nl->Second(t)); } inline bool isFull() const{ return content.size() >=maxSize; } inline void append(Tuple* tup, bool incref=true){ if(incref){ tup->IncReference(); } content.push_back(tup); } inline size_t numberOfTuples() const{ return content.size(); } inline size_t getMaxSize() const{ return maxSize; } inline Tuple* get(int i) const{ return content[i]; } inline size_t size() const{ return content.size(); } inline bool empty() const{ return content.empty(); } inline void set(size_t i, Tuple* t){ content[i] = t; } inline void reduce(size_t s){ if(sTwoElemList ( nl->FourElemList ( nl->StringAtom("Signature"), nl->StringAtom("Example Type List"), nl->StringAtom("List Rep"), nl->StringAtom("Example List")), nl->FourElemList ( nl->StringAtom("-> SIMPLE"), nl->StringAtom(BasicType()), nl->StringAtom("(int tuple*)"), nl->StringAtom("(18000 ( (23 \"Secondo\")))") ))); } static Word In( const ListExpr typeInfo, const ListExpr instance, const int errorPos, ListExpr& errorInfo, bool& correct ){ correct = false; Word res((void*)0); if(!nl->HasLength(instance,2)){ return res; } if(nl->AtomType(nl->First(instance))!=IntType){ return res; } int size = nl->IntValue(nl->First(instance)); if(size <0){ return res; } TupleVector* tv = new TupleVector(size); ListExpr tuples = nl->Second(instance); ListExpr tupleList = nl->TwoElemList( listutils::basicSymbol(), nl->Second(typeInfo)); while(!nl->IsEmpty(tuples)){ if(tv->isFull()){ delete tv; return res; } ListExpr tuple = nl->First(tuples); tuples = nl->Rest(tuples); Tuple* t = Tuple::In(tupleList, tuple, errorPos,errorInfo, correct); if(!t){ delete tv; return res; } tv->append(t, false); } res.addr = tv; correct = true; return res; } static ListExpr Out(ListExpr typeInfo, Word value){ TupleVector* tv = (TupleVector*) value.addr; ListExpr s = nl->IntAtom(tv->maxSize); if(tv->content.empty()){ return nl->TwoElemList(s, nl->TheEmptyList()); } ListExpr tinfo = nl->TwoElemList( listutils::basicSymbol(), nl->Second(typeInfo)); ListExpr ts = nl->OneElemList(tv->content[0]->Out(tinfo)); ListExpr last = ts; for(size_t i=1;icontent.size();i++){ last = nl->Append(last, tv->content[i]->Out(tinfo)); } return nl->TwoElemList(s, ts); } static Word Create(ListExpr typeInfo){ return SetWord(new TupleVector(1)); } static void Delete(ListExpr typeInfo, Word& value){ delete (TupleVector*) value.addr; value.addr = 0; } static bool Open( SmiRecord& valueRecord, size_t& offset, const ListExpr typeInfo, Word& value ) { size_t size; bool ok = (valueRecord.Read(&size,sizeof(size_t),offset) == sizeof(size_t)); offset += sizeof(size_t); size_t numberOfTuples; ok &= valueRecord.Read(&numberOfTuples, sizeof(size_t), offset) ==sizeof(size_t); offset *= sizeof(size_t); if(!ok) return false; TupleVector* tv = new TupleVector(size); ListExpr tinfo = nl->TwoElemList( listutils::basicSymbol(), nl->Second(typeInfo)); SecondoCatalog* ctlg = SecondoSystem::GetCatalog(); ListExpr numType = ctlg->NumericType(tinfo); TupleType* tt = new TupleType(numType); for(size_t i=0;iReadFromBin(0, buffer ); tv->append(res, false); delete[] buffer; } tt->DeleteIfAllowed(); value.addr = tv; return true; } static bool Save( SmiRecord& valueRecord, size_t& offset, const ListExpr typeInfo, Word& value ) { /* ListExpr tinfo = nl->TwoElemList( listutils::basicSymbol(), nl->Second(typeInfo)); */ TupleVector* tv = (TupleVector*) value.addr; size_t s = tv->getMaxSize(); valueRecord.Write(&s,sizeof(size_t), offset); offset += sizeof(size_t); s = tv->numberOfTuples(); valueRecord.Write(&s,sizeof(size_t), offset); offset += sizeof(size_t); size_t coreSize; size_t extensionSize; size_t flobSize; for(size_t i=0;iget(i); size_t blocksize = tuple->GetBlockSize(coreSize, extensionSize, flobSize); char* buffer = new char[blocksize]; tuple->WriteToBin(buffer, coreSize, extensionSize, flobSize); valueRecord.Write(&blocksize,sizeof(size_t),offset); offset+=sizeof(size_t); valueRecord.Write(buffer,blocksize,offset); offset +=blocksize; delete[] buffer; } return true; } static void Close( const ListExpr typeInfo, Word& w ) { delete (TupleVector*) w.addr; w.addr = 0; } static Word Clone( const ListExpr typeInfo, const Word& w ){ return Word(new TupleVector( * ((TupleVector*)w.addr))); } static void* Cast( void* addr ) { return new (addr)TupleVector; } static bool TypeCheck(ListExpr type, ListExpr& errorInfo){ return checkType(type); } static int SizeOf() { return 3000; } private: TupleVector() {} vector content; //size_t size; size_t maxSize; }; TypeConstructor TupleVectorTC( TupleVector::BasicType(), // name of the type TupleVector::Property, // property function TupleVector::Out, TupleVector::In, // out and in function 0, 0, // deprecated, don't think about it TupleVector::Create, TupleVector::Delete, // creation and deletion TupleVector::Open, TupleVector::Save, // open and save functions TupleVector::Close, TupleVector::Clone, // close and clone functions TupleVector::Cast, // cast function TupleVector::SizeOf, // sizeOf function TupleVector::TypeCheck); // type checking function ListExpr feedvTM(ListExpr args){ // relation x size if(!nl->HasLength(args,2)){ return listutils::typeError("2 arguments expected"); } if(!Relation::checkType(nl->First(args))){ return listutils::typeError("first argument has to be a relation"); } if(!CcInt::checkType(nl->Second(args))){ return listutils::typeError("second arg must be an integer"); } ListExpr attrList = nl->Second(nl->Second(nl->First(args))); return nl->TwoElemList( listutils::basicSymbol >(), nl->TwoElemList( listutils::basicSymbol(), attrList)); } class feedvInfo{ public: feedvInfo(Relation* _rel, int _size) : size(_size) { iter = _rel->MakeScan(); //size = size * 1024; // in kB } ~feedvInfo(){ delete iter; } TupleVector* next(){ Tuple* tup = iter->GetNextTuple(); if(tup==0){ return 0; } TupleVector* res = new TupleVector(size); res->append(tup,false); while( !res->isFull() && ((tup=iter->GetNextTuple())!=0) ) { res->append(tup,false); } return res; } private: int size; GenericRelationIterator* iter; }; int feedvVM( Word* args, Word& result, int message, Word& local, Supplier s ){ feedvInfo* li = (feedvInfo*) local.addr; switch(message){ case OPEN: { if(li){ delete li; } CcInt* sizeS = (CcInt*) args[1].addr; int size = sizeS->IsDefined()?sizeS->GetValue():0; local.addr = new feedvInfo((Relation*) args[0].addr,size); return 0; } case REQUEST: result.addr = li?li->next():0; return result.addr?YIELD:CANCEL; case CLOSE : if(li){ delete li; local.addr = 0; } return 0; } // invalid message return -1; } OperatorSpec feedvSpec( "rel x int -> stream(tuplev)", "_ feedv[_]", "Transfers a relation into a stream of vectors of tuples." "The second argument specifies the size that can be " "used by a single element of the stream. ", "query ten feedv[23]" ); Operator feedvOp( "feedv", feedvSpec.getStr(), feedvVM, Operator::SimpleSelect, feedvTM ); /* 1.2 Operator count */ ListExpr countTM(ListExpr args){ if(!nl->HasLength(args,1)){ return listutils::typeError("one arg expected"); } if(!Stream::checkType(nl->First(args))){ return listutils::typeError("stream(tuplevector(X)) expected"); } return listutils::basicSymbol(); } template int countVM( Word* args, Word& result, int message, Word& local, Supplier s ){ Stream stream(args[0]); stream.open(); TupleVector* elem; int count = 0; while( (elem = stream.request())){ if(blockcount){ count++; } else { count += elem->numberOfTuples(); } delete elem; } stream.close(); result = qp->ResultStorage(s); ((CcInt*) result.addr)->Set(true,count); return 0; } OperatorSpec countSpec( "stream(tuplevector) -> int", "_ count", "Returns the number of tuples within a stream of tuplevectors", "query ten feedv[23] count" ); Operator countOp( "count", countSpec.getStr(), countVM, Operator::SimpleSelect, countTM ); OperatorSpec countvSpec( "stream(tuplevector) -> int", "_ countv", "Returns the number of vectors in a stream of tuplevectors", "query ten feedv[23] countv" ); Operator countvOp( "countv", countvSpec.getStr(), countVM, Operator::SimpleSelect, countTM ); /* 1.3 feednp feed without any progress */ ListExpr feednpTM(ListExpr args){ if(!nl->HasLength(args,1)){ return listutils::typeError("1 argument expected"); } if(!Relation::checkType(nl->First(args))){ return listutils::typeError("first argument has to be a relation"); } ListExpr tupleList = nl->Second(nl->First(args)); return nl->TwoElemList( listutils::basicSymbol >(), tupleList); } int feednpVM( Word* args, Word& result, int message, Word& local, Supplier s ){ GenericRelationIterator* li = (GenericRelationIterator*) local.addr; switch(message){ case OPEN: if(li) delete li; local.addr = ((Relation*)args[0].addr)->MakeScan(); return 0; case REQUEST: result.addr = li?li->GetNextTuple():0; return result.addr?YIELD:CANCEL; case CLOSE: if(li){ delete li; local.addr = 0; } return 0; } return -1; } OperatorSpec feednpSpec( "rel(X) -> stream(X)", "_ feednp", "Feed without any progress support.", "query ten feednp count" ); Operator feednpOp( "feednp", feednpSpec.getStr(), feednpVM, Operator::SimpleSelect, feednpTM ); /* countnp */ ListExpr countnpTM(ListExpr args){ if(!nl->HasLength(args,1)){ return listutils::typeError("on argument expected"); } if(!Stream::checkType(nl->First(args))){ return listutils::typeError("stream(tuple(X)) expected"); } return listutils::basicSymbol(); } int countnpVM( Word* args, Word& result, int message, Word& local, Supplier s ){ Stream stream(args[0]); stream.open(); Tuple* elem; int count = 0; while( (elem = stream.request())){ count++; elem->DeleteIfAllowed(); } stream.close(); result = qp->ResultStorage(s); ((CcInt*) result.addr)->Set(true,count); return 0; } OperatorSpec countnpSpec( "stream(tuple) -> int", "_ countnp", "Returns the number of tuples within a stream. ", "query ten feed countnp" ); Operator countnpOp( "countnp", countnpSpec.getStr(), countnpVM, Operator::SimpleSelect, countnpTM ); /* 1.4 projectv */ template ListExpr projectvTM(ListExpr args){ if(!nl->HasMinLength(args,2)){ return listutils::typeError("at least 2 arguments expected"); } if(!Stream::checkType(nl->First(args))){ return listutils::typeError("The first argument must be a stream of " + ST::BasicType() ); } ListExpr attrList = nl->Second(nl->Second(nl->First(args))); args = nl->Rest(args); ListExpr appendList = nl->TheEmptyList(); ListExpr appendLast = nl->TheEmptyList(); bool firstE = true; ListExpr resList = nl->TheEmptyList(); ListExpr resLast = nl->TheEmptyList(); while(!nl->IsEmpty(args)){ ListExpr first = nl->First(args); args = nl->Rest(args); if(!listutils::isSymbol(first)){ return listutils::typeError("invalid attribute name detected"); } string name = nl->SymbolValue(first); ListExpr attrType; int pos = listutils::findAttribute(attrList,name,attrType); if(!pos){ return listutils::typeError(name + " is not an attribute of the tuple"); } ListExpr attr = nl->TwoElemList(first, attrType); ListExpr p = nl->IntAtom(pos-1); if(firstE){ appendList = nl->OneElemList(p); appendLast = appendList; resList = nl->OneElemList(attr); resLast = resList; firstE = false; } else { appendLast = nl->Append(appendLast, p); resLast = nl->Append(resLast, attr); } } resList = nl->TwoElemList( listutils::basicSymbol(), resList); resList = nl->TwoElemList( listutils::basicSymbol >(), resList); return nl->ThreeElemList( nl->SymbolAtom(Symbols::APPEND()), appendList, resList); } template class projectvInfo{ public: projectvInfo(Word _stream, vector* _projectList, TupleType* _tt): stream(_stream), projectList(_projectList), tt(_tt){ stream.open(); } ~projectvInfo(){ stream.close(); } inline ST* next(){ return next(stream); } private: Stream stream; vector* projectList; TupleType* tt; TupleVector* next( Stream&){ TupleVector* in = stream.request(); if(in==0){ return 0; } return project(in); } Tuple* next(Stream&){ Tuple* in = stream.request(); if(!in) return 0; Tuple* res = project(in); in->DeleteIfAllowed(); return res; } TupleVector* project(TupleVector* tv){ for(size_t i = 0; isize(); i++){ Tuple* ti = tv->get(i); Tuple* tr = project(ti); tv->set(i,tr); ti->DeleteIfAllowed(); } return tv; } Tuple* project(Tuple* t){ Tuple* res = new Tuple(tt); for(size_t i=0; isize();i++){ res->CopyAttribute(projectList->at(i), t,i); } return res; } }; template int projectvVM( Word* args, Word& result, int message, Word& local, Supplier s ){ projectvInfo* li = (projectvInfo*) local.addr; typedef pair*, TupleType*> globalInfo; switch(message){ case INIT : { return 0; } case FINISH: { globalInfo* gi = (globalInfo*) qp->GetLocal2(s).addr; if(gi){ delete gi->first; gi->second->DeleteIfAllowed(); delete gi; qp->GetLocal2(s).addr=0; } return 0; } case OPEN: { globalInfo* gi = (globalInfo*) qp->GetLocal2(s).addr; if(!gi){ TupleType* tt = new TupleType(nl->Second(GetTupleResultType(s))); int na = qp->GetNoSons(s); int start = (na - 1)/2 +1; vector* pl = new vector(); for(int i=start ; i< na; i++){ pl->push_back(((CcInt*)args[i].addr)->GetValue()); } gi = new globalInfo(pl,tt); qp->GetLocal2(s).addr = gi; } if(li){ delete li; } local.addr = new projectvInfo(args[0],gi->first, gi->second); return 0; } case REQUEST: result.addr= li?li->next():0; return result.addr?YIELD:CANCEL; case CLOSE: { if(li){ delete li; local.addr = 0; } } return 0; } return -1; } OperatorSpec projectvSpec( "stream(tuplevector) x IDENT+ -> stream(tuplevector)", "_ projectv[_] ", "projects the tuples to the given attributes", "query plz feedv[200] projectv[PLZ] count" ); Operator projectvOp( "projectv", projectvSpec.getStr(), projectvVM, Operator::SimpleSelect, projectvTM ); OperatorSpec projectnpSpec( "stream(tuple) x IDENT+ -> stream(tuple)", "_ projectnp[_] ", "projects the tuples to the given attributes", "query plz feed projectnp[PLZ] count" ); Operator projectnpOp( "projectnp", projectnpSpec.getStr(), projectvVM, Operator::SimpleSelect, projectvTM ); /* 1.6 consume */ ListExpr consumeTM(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("stream(tuplevector) expected"); } ListExpr attrList = nl->Second(nl->Second(arg)); return nl->TwoElemList( listutils::basicSymbol(), nl->TwoElemList( listutils::basicSymbol(), attrList)); } int consumeVM( Word* args, Word& result, int message, Word& local, Supplier s ){ GenericRelation* rel = (GenericRelation*)((qp->ResultStorage(s)).addr); if(rel->GetNoTuples() > 0) { rel->Clear(); } Stream stream(args[0]); stream.open(); TupleVector* tv; while( (tv = stream.request())){ for(size_t i=0;isize();i++){ rel->AppendTuple(tv->get(i)); } delete tv; } stream.close(); result.addr = rel; return 0; } OperatorSpec consumeSpec( "stream(tuplevector) -> rel", "_ consume", "Collects the incoming tuples into a relation", " query plz feedv[200] projectv[PLZ] consume" ); Operator consumeOp( "consume", consumeSpec.getStr(), consumeVM, Operator::SimpleSelect, consumeTM ); /* 1.7 TypeMapOperator TVS2T TupleVectorStream to Tuple */ ListExpr TVS2TTM(ListExpr args){ if(!nl->HasMinLength(args,1)){ return listutils::typeError("at least one argument expected"); } ListExpr arg = nl->First(args); if(!Stream::checkType(arg)){ return listutils::typeError("stream of tuplevectors expected"); } ListExpr attrList = nl->Second(nl->Second(arg)); return nl->TwoElemList(listutils::basicSymbol(),attrList); } OperatorSpec TVS2TSpec( "stream(tuplevector(X)) x ... -> tuple(X)", "op(_,_)", "Retrieves the tuple type of a stream of tuple vectors", "TypeMapping Operator for internal usage only." ); Operator TVS2TOp( "TVS2T", TVS2TSpec.getStr(), 0, Operator::SimpleSelect, TVS2TTM ); /* 1.8 Operator filterv */ template ListExpr filtervTM(ListExpr args){ if(!nl->HasLength(args,argnum)){ return listutils::typeError("invalid number of elements"); } if(!Stream::checkType(nl->First(args))){ return listutils::typeError("first argument must be a stream of " + ST::BasicType()); } if(!listutils::isMap<1>(nl->Second(args))){ return listutils::typeError("second argument must be an unary function"); } ListExpr tt = nl->TwoElemList( listutils::basicSymbol(), nl->Second(nl->Second(nl->First(args)))); ListExpr funarg = nl->Second(nl->Second(args)); if(!nl->Equal(funarg,tt)){ return listutils::typeError("function argument and tuple " "type in stream differ"); } if(!CcBool::checkType(nl->Third(nl->Second(args)))){ return listutils::typeError("function result is not of type bool"); } if(argnum == 2){ return nl->ThreeElemList( nl->SymbolAtom(Symbols::APPEND()), nl->OneElemList(nl->BoolAtom(false)), nl->First(args)); } if(!CcBool::checkType(nl->Third(args))){ return listutils::typeError("third argument must be of type bool"); } return nl->First(args); } template class filtervInfo{ public : filtervInfo(Word _stream, Supplier _fun, bool _allowShrink): stream(_stream), fun(_fun), allowShrink(_allowShrink){ stream.open(), argv = qp->Argument(fun); lastTV = 0; lastPos = 0; maxSize = 0; } ~filtervInfo(){ stream.close(); if(lastTV){ while(lastPos < lastTV->size()){ Tuple* tup = lastTV->get(lastPos); lastPos++; tup->DeleteIfAllowed(); } lastTV->reduce(0); delete lastTV; } } inline TupleVector* nextResult( Stream&){ if(allowShrink){ return nextSimple(); } else { return nextFillUp(); } } inline Tuple* nextResult( Stream&){ Tuple* tup; while( (tup=stream.request())){ if(accept(tup)){ return tup; } else { tup->DeleteIfAllowed(); } } return 0; } ST* next(){ return nextResult(stream); } private: Stream stream; Supplier fun; bool allowShrink; ArgVectorPointer argv; size_t maxSize; Word funRes; TupleVector* lastTV; size_t lastPos; TupleVector* nextSimple(){ TupleVector* in; while( (in = stream.request())){ int writePos = 0; for(size_t i=0;isize();i++){ if(accept(in->get(i))){ in->set(writePos, in->get(i)); writePos++; } else { in->get(i)->DeleteIfAllowed(); } } if(writePos>0){ // in is nonempty in->reduce(writePos); return in; } else { in->reduce(0); delete in; } } return 0; } bool accept(Tuple* t){ (*argv)[0] = t; qp->Request(fun,funRes); CcBool* r = (CcBool*) funRes.addr; return r->IsDefined() && r->GetValue(); } TupleVector* nextFillUp(){ if(maxSize==0) { // first call lastTV = stream.request(); lastPos = 0; if(!lastTV){ return 0; } maxSize = lastTV->getMaxSize(); if(maxSize==0) maxSize=1; } if(!lastTV) { return 0; } return fillUp(); } TupleVector* fillUp(){ TupleVector* res = new TupleVector(maxSize); while(true){ while(lastPos < lastTV->size()){ Tuple* tup = lastTV->get(lastPos); lastPos++; if(accept(tup)){ res->append(tup,false); if(res->isFull()){ return res; } } else { tup->DeleteIfAllowed(); } } lastTV->reduce(0); delete lastTV; lastTV = stream.request(); lastPos = 0; if(!lastTV){ if(!res->empty()){ return res; } else { delete res; return 0; } } } } }; template int filtervVM( Word* args, Word& result, int message, Word& local, Supplier s ){ filtervInfo* li = (filtervInfo*) local.addr; switch(message){ case OPEN : { if(li){ delete li; } CcBool* as1 = (CcBool*) args[2].addr; bool as = as1->IsDefined() && as1->GetValue(); local.addr = new filtervInfo(args[0],args[1].addr,as); return 0; } case REQUEST: result.addr = li?li->next():0; return result.addr?YIELD:CANCEL; case CLOSE : if(li){ delete li; local.addr = 0; } return 0; } return -1; } OperatorSpec filtervSpec( "stream(tuplevector(X)) x (fun(tuple(X)->bool) " "x bool -> stream(tuplevector(X))", "_ filterv[fun,_]", "removes such tuples in the stream that not fulfill the condition ", "The boolean argument specifies whether is is allowed to " "transfer non filled tuplevectors.", "query plz feedv filterv[ . PLZ < 1900, TRUE] count" ); Operator filtervOp( "filterv", filtervSpec.getStr(), filtervVM, Operator::SimpleSelect, filtervTM ); OperatorSpec filternpSpec( "(stream(tuple) x (tuple->bool) -> stream(tuple)", " _ filternp[fun] ", " Removes all tuples from a stream not fulfilling a given condition." " Supports no progress.", " query plz feed filternp[.PLZ < 3000] count" ); Operator filternpOp( "filternp", filternpSpec.getStr(), filtervVM, Operator::SimpleSelect, filtervTM ); /* 1.10 Conversion into a tuple stream */ ListExpr tvs2tsTM(ListExpr args){ if(!nl->HasLength(args,1)){ return listutils::typeError("1 argument expected"); } if(!Stream::checkType(nl->First(args))){ return listutils::typeError("expected a stream of tuple vectors"); } ListExpr attrList = nl->Second(nl->Second(nl->First(args))); return nl->TwoElemList( listutils::basicSymbol > (), nl->TwoElemList(listutils::basicSymbol(), attrList)); } class tvs2tsInfo{ public: tvs2tsInfo( Word _stream ): stream(_stream), lastPos(0){ stream.open(); lastTV = stream.request(); } ~tvs2tsInfo(){ stream.close(); if(lastTV){ for(size_t i = lastPos; i < lastTV->size();i++){ lastTV->get(i)->DeleteIfAllowed(); } lastTV->reduce(0); delete lastTV; } } Tuple* next(){ while( lastTV ){ if(lastPos < lastTV->size()){ Tuple* res = lastTV->get(lastPos); lastPos++; return res; } lastTV->reduce(0); delete lastTV; lastTV = stream.request(); lastPos = 0; } return 0; } private: Stream stream; size_t lastPos; TupleVector* lastTV; }; int tvs2tsVM( Word* args, Word& result, int message, Word& local, Supplier s ){ tvs2tsInfo* li = (tvs2tsInfo*) local.addr; switch(message){ case OPEN : { if(li){ delete li; } local.addr = new tvs2tsInfo(args[0]); return 0; } case REQUEST: result.addr = li?li->next():0; return result.addr?YIELD:CANCEL; case CLOSE : if(li){ delete li; local.addr = 0; } return 0; } return -1; } OperatorSpec tvs2tsSpec( "stream(tuplevector) -> stream(tuple) ", " _ tvs2ts", " Converts a stream of tuple vectors into a stream of tuples", " query plz feedv[200] tvs2ts count" ); Operator tvs2tsOp( "tvs2ts", tvs2tsSpec.getStr(), tvs2tsVM, Operator::SimpleSelect, tvs2tsTM ); /* 2.21 Operator ts2tvs */ ListExpr ts2tvsTM(ListExpr args){ if(!nl->HasLength(args,2)){ return listutils::typeError("two arguments expected"); } if(!Stream::checkType(nl->First(args))){ return listutils::typeError("first argument has to be a tuple stream"); } if(!CcInt::checkType(nl->Second(args))){ return listutils::typeError("second arg must be an integer"); } ListExpr attrList = nl->Second(nl->Second(nl->First(args))); return nl->TwoElemList( listutils::basicSymbol >(), nl->TwoElemList( listutils::basicSymbol(), attrList)); } class ts2tvsInfo{ public: ts2tvsInfo(Word _stream, int _maxSize): stream(_stream), maxSize(_maxSize){ stream.open(); } ~ts2tvsInfo(){ stream.close(); } TupleVector* next(){ Tuple* tup = stream.request(); if(!tup){ return 0; } TupleVector* res = new TupleVector(maxSize); res->append(tup,false); while(!res->isFull() && ((tup=stream.request())!=0)){ res->append(tup,false); } return res; } private: Stream stream; size_t maxSize; }; int ts2tvsVM( Word* args, Word& result, int message, Word& local, Supplier s ){ ts2tvsInfo* li = (ts2tvsInfo*) local.addr; switch(message){ case OPEN: { if(li){ delete li; local.addr = 0; } CcInt* cSize = (CcInt*) args[1].addr; int size = cSize->IsDefined()?cSize->GetValue():0; if(size > 0){ local.addr = new ts2tvsInfo(args[0],size); } return 0; } case REQUEST: result.addr = li?li->next():0; return result.addr?YIELD:CANCEL; case CLOSE : if(li){ delete li; local.addr = 0; } return 0; } return -1; } OperatorSpec ts2tvsSpec( "stream(tuple) x int -> stream(tuplevector)", "_ ts2tvs[_] ", "Converts a stream of tuples into a stream of tuplevectors " "having a specified size", " query plz feed ts2tvs[200] count" ); Operator ts2tvsOp( "ts2tvs", ts2tvsSpec.getStr(), ts2tvsVM, Operator::SimpleSelect, ts2tvsTM ); /* 2.11 Operator ~extendv~ StreamType may be Tuple or TupleVector */ template ListExpr extendvTM(ListExpr args){ if(!nl->HasLength(args,2)){ return listutils::typeError("stream("+ StreamType::BasicType() + ") x funlist expected"); } if(!Stream::checkType(nl->First(args))){ return listutils::typeError("first arg is not a stream of " + StreamType::BasicType()); } if(nl->AtomType(nl->Second(args))!=NoAtom){ return listutils::typeError("second arg is not a (fun) list"); } ListExpr attrList = nl->Second(nl->Second(nl->First(args))); // copy old attribute list ListExpr newAttrList = nl->OneElemList(nl->First(attrList)); ListExpr last = newAttrList; ListExpr rest = nl->Rest(attrList); while(!nl->IsEmpty(rest)){ last = nl->Append(last, nl->First(rest)); rest = nl->Rest(rest); } ListExpr tupleType = nl->TwoElemList( listutils::basicSymbol(), attrList); rest = nl->Second(args); set used; while(!nl->IsEmpty(rest)){ ListExpr first = nl->First(rest); rest = nl->Rest(rest); if(!nl->HasLength(first,2)){ return listutils::typeError("invalid named function found"); } ListExpr nameL = nl->First(first); if(nl->AtomType(nameL) != SymbolType){ return listutils::typeError("invalid name for an attribute: " + nl->ToString(nameL)); } string name = nl->SymbolValue(nameL); ListExpr attrType; if(listutils::findAttribute(attrList, name, attrType)!=0){ return listutils::typeError("attribute " + name + " already present in original tuple"); } if(used.find(name)!=used.end()){ return listutils::typeError("attributename " + name + " used twice"); } used.insert(name); ListExpr fun = nl->Second(first); if(!listutils::isMap<1>(fun)){ return listutils::typeError("definition for " + name + " is not an unary function"); } if(!nl->Equal(tupleType,nl->Second(fun))){ return listutils::typeError("tuple type and function argument type for " + name + " differ"); } attrType = nl->Third(fun); if(!Attribute::checkType(attrType)){ return listutils::typeError("function result for " + name + " is not an attribute"); } ListExpr l = nl->TwoElemList(nameL, attrType); last = nl->Append(last,l); } ListExpr resType = nl->TwoElemList( listutils::basicSymbol >(), nl->TwoElemList(listutils::basicSymbol(), newAttrList)); ListExpr appendList = nl->OneElemList(nl->IntAtom(0)); last = appendList; int length = nl->ListLength(attrList); for(int i=1;iAppend(last, nl->IntAtom(i)); } return nl->ThreeElemList(nl->SymbolAtom(Symbols::APPEND()), appendList, resType); } template class projectExtendInfo{ public: projectExtendInfo(Word _stream, vector& _projectionList, vector& _functions, TupleType* _tt): stream(_stream), projectionList(_projectionList), functions(_functions), tt(_tt){ stream.open(); tt->IncReference(); for(size_t i=0;iArgument(functions[i])); } } ~projectExtendInfo(){ tt->DeleteIfAllowed(); stream.close(); } StreamType* next(){ StreamType* in = stream.request(); return in?projectextend(in):0; } private: Stream stream; vector projectionList; vector functions; TupleType* tt; vector funargs; Word funres; TupleVector* projectextend(TupleVector* in){ for(size_t i=0;isize();i++){ Tuple* it = in->get(i); Tuple* ot = projectextend(it); in->set(i,ot); } return in; } Tuple* projectextend(Tuple* in){ Tuple* out = new Tuple(tt); // projectionList for(size_t i=0;iCopyAttribute(projectionList[i],in,i); } for(size_t i = 0; iRequest(functions[i],funres); out->PutAttribute(projectionList.size()+i, ((Attribute*) funres.addr)->Clone()); } in->DeleteIfAllowed(); return out; } }; struct projectExtendGlobalInfo{ projectExtendGlobalInfo(){ tt = 0; projectList = 0; funList = 0; } ~projectExtendGlobalInfo(){ if(tt) tt->DeleteIfAllowed(); if(projectList) delete projectList; if(funList) delete funList; } TupleType* tt; vector* projectList; vector* funList; }; template int projectextendVM( Word* args, Word& result, int message, Word& local, Supplier s ){ typedef projectExtendInfo localInfo_t; localInfo_t* li = (localInfo_t*) local.addr; switch(message){ case INIT: { projectExtendGlobalInfo* gi = new projectExtendGlobalInfo(); ListExpr resType = qp->GetType(s); ListExpr attrList = nl->Second(nl->Second(resType)); ListExpr tupleType = nl->TwoElemList(listutils::basicSymbol(), attrList); ListExpr ttl = SecondoSystem::GetCatalog()->NumericType(tupleType); TupleType* tt = new TupleType(ttl); gi->tt = tt; qp->GetLocal2(s).addr=gi; return 0; } case FINISH: { projectExtendGlobalInfo* gi = (projectExtendGlobalInfo*) qp->GetLocal2(s).addr; if(gi){ delete gi; qp->GetLocal2(s).addr=0; } return 0; } case OPEN: { if(li){ delete li; local.addr = 0; } projectExtendGlobalInfo* gi = (projectExtendGlobalInfo*) qp->GetLocal2(s).addr; if(!gi){ return 0; // should never happen } if(!gi->projectList){ vector* v = new vector(); int start = useProject?3:2; for(int i=start; iGetNoSons(s);i++){ int p = ((CcInt*) args[i].addr)->GetValue(); v->push_back(p); } gi->projectList = v; Supplier fl = qp->GetSon(s,useProject?2:1); vector* funs = new vector(); for(int i=0;iGetNoSons(fl);i++){ Supplier namedFun = qp->GetSon(fl,i); Supplier fun = qp->GetSon(namedFun,1); funs->push_back(fun); } gi->funList = funs; } local.addr = new localInfo_t(args[0], *gi->projectList, *gi->funList,gi->tt); return 0; } case REQUEST: result.addr = li?li->next():0; return result.addr?YIELD:CANCEL; case CLOSE: if(li){ delete li; local.addr = 0; } return 0; } return -1; } OperatorSpec extendvSpec( "stream(tuplevector) x funlist -> stream(tuplevector)", " _ extendv[funlist] ", " Extends the tuples within a tuplevector stream " " by applying a set of functions to each tuple.", " query plz feedv[200] extendv[PLZ2 : .PLZ * 2] consume" ); Operator extendvOp( "extendv", extendvSpec.getStr(), projectextendVM, Operator::SimpleSelect, extendvTM ); template ListExpr projectextendTM(ListExpr args){ if(!nl->HasLength(args,3)){ return listutils::typeError("expected stream x projectList, funList"); } if(!Stream::checkType(nl->First(args))){ return listutils::typeError("first arg is not a stream of " +StreamType::BasicType()); } ListExpr pList = nl->Second(args); if(nl->AtomType(pList) != NoAtom){ return listutils::typeError("second argument must be a list of " "projection attributes"); } ListExpr attrList = nl->Second(nl->Second(nl->First(args))); ListExpr tupleList = nl->TwoElemList( listutils::basicSymbol(), attrList); ListExpr appendList = nl->TheEmptyList(); ListExpr lastappend = nl->TheEmptyList(); ListExpr resAttrList = nl->TheEmptyList(); ListExpr lastRes = nl->TheEmptyList(); // process projection list bool isFirst = true; set used; while(!nl->IsEmpty(pList)){ ListExpr pl = nl->First(pList); pList = nl->Rest(pList); if(nl->AtomType(pl) !=SymbolType){ return listutils::typeError("found invalid attribute name in " "projection list"); } string name = nl->SymbolValue(pl); ListExpr attrType; int index = listutils::findAttribute(attrList, name, attrType); if(!index){ return listutils::typeError("attribute " + name + " not found"); } ListExpr attr = nl->TwoElemList(pl, attrType); if(used.find(name)!=used.end()){ return listutils::typeError("name " + name + " used twice"); } used.insert(name); if(isFirst){ appendList = nl->OneElemList(nl->IntAtom(index-1)); lastappend = appendList; resAttrList = nl->OneElemList(attr); lastRes = resAttrList; isFirst = false; } else { lastappend = nl->Append(lastappend, nl->IntAtom(index-1)); lastRes = nl->Append(lastRes, attr); } } // process fun list ListExpr flist = nl->Third(args); if(nl->AtomType(flist) != NoAtom){ return listutils::typeError("expected list of named function as third arg"); } while(!nl->IsEmpty(flist)){ ListExpr nfun = nl->First(flist); flist = nl->Rest(flist); if(!nl->HasLength(nfun,2)){ return listutils::typeError("invalid format for a named function"); } ListExpr fnl = nl->First(nfun); if(nl->AtomType(fnl)!=SymbolType){ return listutils::typeError("invalid name for an attribute"); } string fn = nl->SymbolValue(fnl); if(used.find(fn)!=used.end()){ return listutils::typeError("Attribute name " + fn + " used twice"); } used.insert(fn); ListExpr fun = nl->Second(nfun); if(!listutils::isMap<1>(fun)){ return listutils::typeError("definition of attribute " + fn + " is not an unary function"); } if(!nl->Equal(tupleList, nl->Second(fun))){ return listutils::typeError("tuple type and function argument type for " + fn + "differ"); } ListExpr attrType = nl->Third(fun); if(!Attribute::checkType(attrType)){ return listutils::typeError("result type for " + fn + " in not an attribute"); } ListExpr attr = nl->TwoElemList(fnl, attrType); if(isFirst){ resAttrList = nl->OneElemList(attr); lastRes = resAttrList; isFirst = false; } else { lastRes = nl->Append(lastRes,attr); } } ListExpr resList = nl->TwoElemList( listutils::basicSymbol >(), nl->TwoElemList( listutils::basicSymbol(), resAttrList)); return nl->ThreeElemList(nl->SymbolAtom(Symbols::APPEND()), appendList, resList); } OperatorSpec projectextendSpec( "stream(tuplevector) x projectlist x funList -> stream(tuplevector)", "_ projectextend[plist; fList]", "projects incoming tuples to a subset of their attributes and " "extends this tuple using some named functions.", "query plz feedv[200] projectextendv[ Ort ; PLZ2 : .PLZ * 2] consume" ); Operator projectextendOp( "projectextendv", projectextendSpec.getStr(), projectextendVM, Operator::SimpleSelect, projectextendTM ); OperatorSpec extendnpSpec( "stream(tuple) x funlist -> stream(tuple)", " _ extendnp[funlist] ", " Extends the tuples within a tuple stream " " by applying a set of functions to each tuple.", " query plz feed extendinp[PLZ2 : .PLZ * 2] consume" ); Operator extendnpOp( "extendnp", extendnpSpec.getStr(), projectextendVM, Operator::SimpleSelect, extendvTM ); OperatorSpec projectextendnpSpec( "stream(tuple) x projectlist x funlist -> stream(tuple)", " _ extendnp[projectList;funlist] ", " Extends the projected tuples within a tuple stream " " by applying a set of functions to each tuple.", " query plz feed projectextendnp[Ort;PLZ2 : .PLZ * 2] consume" ); Operator projectextendnpOp( "projectextendnp", projectextendnpSpec.getStr(), projectextendVM, Operator::SimpleSelect, projectextendTM ); class TupleVectorAlgebra : public Algebra { public: TupleVectorAlgebra() : Algebra() { AddTypeConstructor(&TupleVectorTC); TupleVectorTC.AssociateKind(Kind::SIMPLE()); AddOperator(&feedvOp); AddOperator(&countOp); AddOperator(&countvOp); AddOperator(&projectvOp); projectvOp.enableInitFinishSupport(); AddOperator(&consumeOp); AddOperator(&filtervOp); AddOperator(&tvs2tsOp); AddOperator(&ts2tvsOp); AddOperator(&extendvOp); extendvOp.enableInitFinishSupport(); AddOperator(&projectextendOp); projectextendOp.enableInitFinishSupport(); AddOperator(&TVS2TOp); AddOperator(&feednpOp); AddOperator(&countnpOp); AddOperator(&filternpOp); AddOperator(&extendnpOp); extendnpOp.enableInitFinishSupport(); AddOperator(&projectextendnpOp); projectextendnpOp.enableInitFinishSupport(); AddOperator(&projectnpOp); projectnpOp.enableInitFinishSupport(); } }; } // namespace tuplevector extern "C" Algebra* InitializeTupleVectorAlgebra( NestedList* nlRef, QueryProcessor* qpRef ) { return new tuplevector::TupleVectorAlgebra; }