5942 lines
149 KiB
C++
5942 lines
149 KiB
C++
|
|
/*
|
||
|
|
----
|
||
|
|
This file is part of SECONDO.
|
||
|
|
|
||
|
|
Copyright (C) 2004, University in Hagen, Department of Computer Science,
|
||
|
|
Database Systems for New Applications.
|
||
|
|
|
||
|
|
SECONDO is free software; you can redistribute it and/or modify
|
||
|
|
it under the terms of the GNU General Public License as published by
|
||
|
|
the Free Software Foundation; either version 2 of the License, or
|
||
|
|
(at your option) any later version.
|
||
|
|
|
||
|
|
SECONDO is distributed in the hope that it will be useful,
|
||
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
|
GNU General Public License for more details.
|
||
|
|
|
||
|
|
You should have received a copy of the GNU General Public License
|
||
|
|
along with SECONDO; if not, write to the Free Software
|
||
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||
|
|
----
|
||
|
|
|
||
|
|
//paragraph [1] Title: [{\Large \bf \begin{center}] [\end{center}}]
|
||
|
|
//paragraph [10] Footnote: [{\footnote{] [}}]
|
||
|
|
//[TOC] [\tableofcontents]
|
||
|
|
|
||
|
|
[1] Implementation of Module Relation Algebra Main Memory
|
||
|
|
|
||
|
|
[1] Using Storage Manager Berkeley DB
|
||
|
|
|
||
|
|
June 1996 Claudia Freundorfer
|
||
|
|
|
||
|
|
May 2002 Frank Hoffmann port to C++
|
||
|
|
|
||
|
|
November 7, 2002 RHG Corrected the type mapping of ~tcount~.
|
||
|
|
|
||
|
|
November 30, 2002 RHG Introduced a function ~RelPersistValue~ instead of
|
||
|
|
~DefaultPersistValue~ which keeps relations that have been built in memory in a
|
||
|
|
small cache, so that they need not be rebuilt from then on.
|
||
|
|
|
||
|
|
December 2005, Victor Almeida deleted the deprecated algebra levels
|
||
|
|
(~executable~, ~descriptive~, and ~hibrid~). Only the executable
|
||
|
|
level remains. Models are also removed from type constructors.
|
||
|
|
|
||
|
|
[TOC]
|
||
|
|
|
||
|
|
2 Auxilary Functions
|
||
|
|
|
||
|
|
1.2 Function ~TypeOfRelAlgSymbol~
|
||
|
|
|
||
|
|
Transforms a list expression ~symbol~ into one of the values of
|
||
|
|
type ~RelationType~. ~Symbol~ is allowed to be any list. If it is not one
|
||
|
|
of these symbols, then the value ~error~ is returned.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
#include <set>
|
||
|
|
#include <time.h>
|
||
|
|
|
||
|
|
|
||
|
|
#include "OldRelationAlgebra.h"
|
||
|
|
#include "Algebras/Relation-C++/RelationAlgebra.h"
|
||
|
|
#include "CPUTimeMeasurer.h"
|
||
|
|
#include "QueryProcessor.h"
|
||
|
|
#include "LogMsg.h"
|
||
|
|
#include "ListUtils.h"
|
||
|
|
#include "Symbols.h"
|
||
|
|
|
||
|
|
extern NestedList* nl;
|
||
|
|
extern QueryProcessor* qp;
|
||
|
|
|
||
|
|
extern int ccTuplesCreated;
|
||
|
|
extern int ccTuplesDeleted;
|
||
|
|
|
||
|
|
extern TypeConstructor ccreltuple;
|
||
|
|
extern TypeConstructor ccrelprel;
|
||
|
|
|
||
|
|
// type mapping functions implemented in ExtRelationAlgebra.cpp
|
||
|
|
extern ListExpr GroupByTypeMap2(ListExpr args, const bool memoryImpl = false);
|
||
|
|
|
||
|
|
|
||
|
|
using namespace std;
|
||
|
|
|
||
|
|
namespace oldrelation{
|
||
|
|
|
||
|
|
static CcRelationType CcTypeOfRelAlgSymbol (ListExpr symbol)
|
||
|
|
{
|
||
|
|
string s;
|
||
|
|
|
||
|
|
if (nl->AtomType(symbol) == SymbolType)
|
||
|
|
{
|
||
|
|
s = nl->SymbolValue(symbol);
|
||
|
|
if (s == CcRel::BasicType() ) return mrel;
|
||
|
|
if (s == CcTuple::BasicType() ) return mtuple;
|
||
|
|
if (s == Symbol::STREAM() ) return mstream;
|
||
|
|
if (s == Symbol::MAP() ) return mmap;
|
||
|
|
if (s == CcBool::BasicType() ) return mbool;
|
||
|
|
}
|
||
|
|
return merror;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
5.6 Function ~FindAttribute~
|
||
|
|
|
||
|
|
Here ~list~ should be a list of pairs of the form (~name~,~datatype~).
|
||
|
|
The function ~FindAttribute~ determines whether ~attrname~ occurs as one of
|
||
|
|
the names in this list. If so, the index in the list (counting from 1)
|
||
|
|
is returned and the corresponding datatype is returned in ~attrtype~.
|
||
|
|
Otherwise 0 is returned. Used in operator ~attr~.
|
||
|
|
|
||
|
|
*/
|
||
|
|
int CcFindAttribute( ListExpr list, string attrname,
|
||
|
|
ListExpr& attrtype, NestedList* nl)
|
||
|
|
{
|
||
|
|
ListExpr first, rest;
|
||
|
|
int j;
|
||
|
|
string name;
|
||
|
|
|
||
|
|
if (nl->IsAtom(list))
|
||
|
|
return 0;
|
||
|
|
rest = list;
|
||
|
|
j = 1;
|
||
|
|
while (!nl->IsEmpty(rest))
|
||
|
|
{
|
||
|
|
first = nl->First(rest);
|
||
|
|
rest = nl->Rest(rest);
|
||
|
|
if ((nl->ListLength(first) == 2) &&
|
||
|
|
(nl->AtomType(nl->First(first)) == SymbolType))
|
||
|
|
{
|
||
|
|
name = nl->SymbolValue(nl->First(first));
|
||
|
|
if (name == attrname)
|
||
|
|
{
|
||
|
|
attrtype = nl->Second(first);
|
||
|
|
return j;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
return 0; // typeerror
|
||
|
|
j++;
|
||
|
|
}
|
||
|
|
return 0; // attrname not found
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
5.6 Function ~ConcatLists~
|
||
|
|
|
||
|
|
Concatenates two lists.
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr CcConcatLists( ListExpr list1, ListExpr list2)
|
||
|
|
{
|
||
|
|
if (nl->IsEmpty(list1))
|
||
|
|
{
|
||
|
|
return list2;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
return nl->Cons(nl->First(list1), CcConcatLists(nl->Rest(list1), list2));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
5.6 Function ~IsTupleDescription~
|
||
|
|
|
||
|
|
Checks wether a ListExpression is of the form
|
||
|
|
((a1 t1) ... (ai ti)).
|
||
|
|
|
||
|
|
*/
|
||
|
|
bool CcIsTupleDescription(ListExpr a, NestedList* nl)
|
||
|
|
{
|
||
|
|
ListExpr rest = a;
|
||
|
|
ListExpr current;
|
||
|
|
|
||
|
|
while(!nl->IsEmpty(rest))
|
||
|
|
{
|
||
|
|
current = nl->First(rest);
|
||
|
|
rest = nl->Rest(rest);
|
||
|
|
if((nl->ListLength(current) == 2)
|
||
|
|
&& (nl->IsAtom(nl->First(current)))
|
||
|
|
&& (nl->AtomType(nl->First(current)) == SymbolType)
|
||
|
|
&& (nl->IsAtom(nl->Second(current)))
|
||
|
|
&& (nl->AtomType(nl->Second(current)) == SymbolType))
|
||
|
|
{
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
5.6 Function ~AttributesAreDisjoint~
|
||
|
|
|
||
|
|
Checks wether two ListExpressions are of the form
|
||
|
|
((a1 t1) ... (ai ti)) and ((b1 d1) ... (bj dj))
|
||
|
|
and wether the ai and the bi are disjoint.
|
||
|
|
|
||
|
|
*/
|
||
|
|
bool CcAttributesAreDisjoint(ListExpr a, ListExpr b)
|
||
|
|
{
|
||
|
|
set<string> aNames;
|
||
|
|
ListExpr rest = a;
|
||
|
|
ListExpr current;
|
||
|
|
|
||
|
|
while(!nl->IsEmpty(rest))
|
||
|
|
{
|
||
|
|
current = nl->First(rest);
|
||
|
|
rest = nl->Rest(rest);
|
||
|
|
if((nl->ListLength(current) == 2)
|
||
|
|
&& (nl->IsAtom(nl->First(current)))
|
||
|
|
&& (nl->AtomType(nl->First(current)) == SymbolType)
|
||
|
|
&& (nl->IsAtom(nl->Second(current)))
|
||
|
|
&& (nl->AtomType(nl->Second(current)) == SymbolType))
|
||
|
|
{
|
||
|
|
aNames.insert(nl->SymbolValue(nl->First(current)));
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
rest = b;
|
||
|
|
while(!nl->IsEmpty(rest))
|
||
|
|
{
|
||
|
|
ListExpr current = nl->First(rest);
|
||
|
|
rest = nl->Rest(rest);
|
||
|
|
if((nl->ListLength(current) == 2)
|
||
|
|
&& (nl->IsAtom(nl->First(current)))
|
||
|
|
&& (nl->AtomType(nl->First(current)) == SymbolType)
|
||
|
|
&& (nl->IsAtom(nl->Second(current)))
|
||
|
|
&& (nl->AtomType(nl->Second(current)) == SymbolType))
|
||
|
|
{
|
||
|
|
if(aNames.find(nl->SymbolValue(nl->First(current))) != aNames.end())
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
4 Operators
|
||
|
|
|
||
|
|
4.2 Selection function for type operators
|
||
|
|
|
||
|
|
The selection function of a type operator always returns -1.
|
||
|
|
|
||
|
|
*/
|
||
|
|
static int CcTypeOperatorSelect(ListExpr args)
|
||
|
|
{
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
6.1 Type Operator ~TUPLE~
|
||
|
|
|
||
|
|
Type operators are used only for inferring argument types of parameter
|
||
|
|
functions. They have a type mapping but no evaluation function.
|
||
|
|
|
||
|
|
6.1.1 Type mapping function of operator ~TUPLE~
|
||
|
|
|
||
|
|
Extract tuple type from a stream or relation type given as the first argument.
|
||
|
|
|
||
|
|
---- ((stream x) ...) -> x
|
||
|
|
((mrel x) ...) -> x
|
||
|
|
----
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr CcTUPLETypeMap(ListExpr args)
|
||
|
|
{
|
||
|
|
ListExpr first;
|
||
|
|
if(nl->ListLength(args) >= 1)
|
||
|
|
{
|
||
|
|
first = nl->First(args);
|
||
|
|
if(nl->ListLength(first) == 2 )
|
||
|
|
{
|
||
|
|
if ((CcTypeOfRelAlgSymbol(nl->First(first)) == mstream) ||
|
||
|
|
(CcTypeOfRelAlgSymbol(nl->First(first)) == mrel))
|
||
|
|
return nl->Second(first);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
||
|
|
}
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Specification of operator ~TUPLE~
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string CcTUPLESpec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
||
|
|
"\"Remarks\" ) "
|
||
|
|
"( <text>((stream x)...) -> x, ((mrel x)...) -> "
|
||
|
|
"x</text--->"
|
||
|
|
"<text>type operator</text--->"
|
||
|
|
"<text>Extract tuple type from a stream or "
|
||
|
|
"relation type given as the first argument."
|
||
|
|
"</text--->"
|
||
|
|
"<text>not for use with sos-syntax</text--->"
|
||
|
|
" ) )";
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Definition of operator ~TUPLE~
|
||
|
|
|
||
|
|
*/
|
||
|
|
Operator ccrelTUPLE (
|
||
|
|
"TUPLE", // name
|
||
|
|
CcTUPLESpec, // specification
|
||
|
|
0, // no value mapping
|
||
|
|
CcTypeOperatorSelect, // trivial selection function
|
||
|
|
CcTUPLETypeMap // type mapping
|
||
|
|
);
|
||
|
|
/*
|
||
|
|
|
||
|
|
6.1 Type Operator ~TUPLE2~
|
||
|
|
|
||
|
|
6.1.1 Type mapping function of operator ~TUPLE2~
|
||
|
|
|
||
|
|
Extract tuple type from a stream or relation type given as the second argument.
|
||
|
|
|
||
|
|
---- ((stream x) (stream y) ...) -> y
|
||
|
|
((mrel x) (mrel y) ...) -> y
|
||
|
|
----
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr CcTUPLE2TypeMap(ListExpr args)
|
||
|
|
{
|
||
|
|
ListExpr second;
|
||
|
|
if(nl->ListLength(args) >= 2)
|
||
|
|
{
|
||
|
|
second = nl->Second(args);
|
||
|
|
if(nl->ListLength(second) == 2 )
|
||
|
|
{
|
||
|
|
if ((CcTypeOfRelAlgSymbol(nl->First(second)) == mstream) ||
|
||
|
|
(CcTypeOfRelAlgSymbol(nl->First(second)) == mrel))
|
||
|
|
return nl->Second(second);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
||
|
|
}
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Specification of operator ~TUPLE2~
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string CcTUPLE2Spec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
||
|
|
"\"Remarks\" ) "
|
||
|
|
"( <text><text>((stream x) (stream y) ...) -> y, "
|
||
|
|
"((mrel x) (mrel y) ...) -> y</text--->"
|
||
|
|
"<text>type operator</text--->"
|
||
|
|
"<text>Extract tuple type from a stream or "
|
||
|
|
"relation"
|
||
|
|
" type given as the second argument.</text--->"
|
||
|
|
"<text>not for use with sos-syntax</text--->"
|
||
|
|
") )";
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Definition of operator ~TUPLE2~
|
||
|
|
|
||
|
|
*/
|
||
|
|
Operator ccrelTUPLE2 (
|
||
|
|
"TUPLE2", // name
|
||
|
|
CcTUPLE2Spec, // specification
|
||
|
|
0, // no value mapping
|
||
|
|
CcTypeOperatorSelect, // trivial selection function
|
||
|
|
CcTUPLE2TypeMap // type mapping
|
||
|
|
);
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
6.1 Type Operator ~Group~
|
||
|
|
|
||
|
|
Type operators are used only for inferring argument types of parameter
|
||
|
|
functions. They have a type mapping but no evaluation function.
|
||
|
|
|
||
|
|
6.1.1 Type mapping function of operator ~group~
|
||
|
|
|
||
|
|
---- ((stream x)) -> (mrel x)
|
||
|
|
----
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr CcGroupTypeMap(ListExpr args)
|
||
|
|
{
|
||
|
|
ListExpr first;
|
||
|
|
ListExpr tupleDesc;
|
||
|
|
|
||
|
|
if(!nl->IsAtom(args) && nl->ListLength(args) >= 1)
|
||
|
|
{
|
||
|
|
first = nl->First(args);
|
||
|
|
if(!nl->IsAtom(first) && nl->ListLength(first) == 2 )
|
||
|
|
{
|
||
|
|
tupleDesc = nl->Second(first);
|
||
|
|
if(CcTypeOfRelAlgSymbol(nl->First(first)) == mstream
|
||
|
|
&& (!nl->IsAtom(tupleDesc))
|
||
|
|
&& (nl->ListLength(tupleDesc) == 2)
|
||
|
|
&& CcTypeOfRelAlgSymbol(nl->First(tupleDesc)) == mtuple
|
||
|
|
&& CcIsTupleDescription(nl->Second(tupleDesc), nl))
|
||
|
|
return
|
||
|
|
nl->TwoElemList(
|
||
|
|
nl->SymbolAtom(CcRel::BasicType()),
|
||
|
|
tupleDesc);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
||
|
|
}
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Specification of operator ~Group~
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string CcGroupSpec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
||
|
|
"\"Remarks\" ) "
|
||
|
|
"( <text>((stream x)) -> (mrel x)</text--->"
|
||
|
|
"<text>type operator</text--->"
|
||
|
|
"<text>Maps stream type to a relation.</text--->"
|
||
|
|
"<text>not for use with sos-syntax</text--->"
|
||
|
|
") )";
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Definition of operator ~group~
|
||
|
|
|
||
|
|
*/
|
||
|
|
Operator ccrelgroup (
|
||
|
|
"GROUP", // name
|
||
|
|
CcGroupSpec, // specification
|
||
|
|
0, // no value mapping
|
||
|
|
CcTypeOperatorSelect, // trivial selection function
|
||
|
|
CcGroupTypeMap // type mapping
|
||
|
|
);
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1 Operator ~feed~
|
||
|
|
|
||
|
|
Produces a stream from a relation by scanning the relation tuple by tuple.
|
||
|
|
|
||
|
|
4.1.1 Type mapping function of operator ~feed~
|
||
|
|
|
||
|
|
A type mapping function takes a nested list as argument. Its contents are
|
||
|
|
type descriptions of an operator's input parameters. A nested list describing
|
||
|
|
the output type of the operator is returned.
|
||
|
|
|
||
|
|
Result type of feed operation.
|
||
|
|
|
||
|
|
---- ((mrel x)) -> (stream x)
|
||
|
|
----
|
||
|
|
|
||
|
|
*/
|
||
|
|
static ListExpr CcFeedTypeMap(ListExpr args)
|
||
|
|
{
|
||
|
|
if(nl->ListLength(args)!=1){
|
||
|
|
return listutils::typeError("One argument expected");
|
||
|
|
}
|
||
|
|
ListExpr mrel = nl->First(args);
|
||
|
|
if(!listutils::isRelDescription2(mrel, CcRel::BasicType())){
|
||
|
|
return listutils::typeError("mrel(x) expected");
|
||
|
|
}
|
||
|
|
return nl->Cons(nl->SymbolAtom(Symbol::STREAM()), nl->Rest(mrel));
|
||
|
|
}
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.2 Value mapping function of operator ~feed~
|
||
|
|
|
||
|
|
*/
|
||
|
|
static int
|
||
|
|
CcFeed(Word* args, Word& result, int message, Word& local, Supplier s)
|
||
|
|
{
|
||
|
|
CcRel* r;
|
||
|
|
CcRelIT* rit;
|
||
|
|
|
||
|
|
switch (message)
|
||
|
|
{
|
||
|
|
case OPEN :
|
||
|
|
r = ((CcRel*)args[0].addr);
|
||
|
|
rit = r->MakeNewScan();
|
||
|
|
|
||
|
|
local.addr = rit;
|
||
|
|
return 0;
|
||
|
|
|
||
|
|
case REQUEST :
|
||
|
|
rit = (CcRelIT*)local.addr;
|
||
|
|
if (!(rit->EndOfScan()))
|
||
|
|
{
|
||
|
|
result = SetWord(rit->GetTuple());
|
||
|
|
rit->Next();
|
||
|
|
return YIELD;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
return CANCEL;
|
||
|
|
}
|
||
|
|
|
||
|
|
case CLOSE :
|
||
|
|
rit = (CcRelIT*)local.addr;
|
||
|
|
if(rit)
|
||
|
|
{
|
||
|
|
delete rit;
|
||
|
|
local = SetWord(Address(0));
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Specification of operator ~feed~
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string CcFeedSpec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
||
|
|
"\"Example\" ) "
|
||
|
|
"( <text>(mrel x) -> (stream x)</text--->"
|
||
|
|
"<text>_ feed</text--->"
|
||
|
|
"<text>Produces a stream from a relation by "
|
||
|
|
"scanning the relation tuple by tuple.</text--->"
|
||
|
|
"<text>query cities feed consume</text--->"
|
||
|
|
") )";
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Definition of operator ~feed~
|
||
|
|
|
||
|
|
Non-overloaded operators are defined by constructing a new instance of
|
||
|
|
class ~Operator~, passing all operator functions as constructor arguments.
|
||
|
|
|
||
|
|
*/
|
||
|
|
Operator ccrelfeed (
|
||
|
|
"feed", // name
|
||
|
|
CcFeedSpec, // specification
|
||
|
|
CcFeed, // value mapping
|
||
|
|
Operator::SimpleSelect, // trivial selection function
|
||
|
|
CcFeedTypeMap // type mapping
|
||
|
|
);
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1 Operator ~sample~
|
||
|
|
|
||
|
|
Produces a stream representing a sample of a relation.
|
||
|
|
|
||
|
|
4.1.1 Function ~MakeRandomSubset~
|
||
|
|
|
||
|
|
Generates a random subset of the numbers 1 ... ~setSize~, the size
|
||
|
|
of which is ~subsetSize~. This function is needed for operator ~sample~.
|
||
|
|
|
||
|
|
The strategy for generating a random subset works as follows: The algorithm
|
||
|
|
maintains a set of already drawn numbers. The algorithm draws a new random
|
||
|
|
number (using the libc random number generator) and adds it to the set of
|
||
|
|
already drawn numbers, if it has not been
|
||
|
|
already drawn. This is repeated until the size of the drawn set equals
|
||
|
|
~subsetSize~. If ~subsetSize~ it not considerably smaller than ~setSize~, e.g.
|
||
|
|
~subsetSize~ = ~setSize~ - 1, this approach becomes very inefficient
|
||
|
|
or may even not terminate, because towards the end of the algorithm
|
||
|
|
it may take a very long (or infinitely long)
|
||
|
|
time until the random number generator hits one of the few numbers,
|
||
|
|
which have not been already drawn. Therefore, if ~subsetSize~ is more
|
||
|
|
than half of ~subSet~, we simple draw a subset of size
|
||
|
|
~setSize~ - ~subsetSize~ and take the complement of that set as result set.
|
||
|
|
|
||
|
|
*/
|
||
|
|
void
|
||
|
|
CcMakeRandomSubset(vector<int>& result, int subsetSize, int setSize)
|
||
|
|
{
|
||
|
|
assert(subsetSize >= 1);
|
||
|
|
assert(setSize >= 2);
|
||
|
|
assert(setSize <= RAND_MAX);
|
||
|
|
assert(setSize > subsetSize);
|
||
|
|
|
||
|
|
set<int> drawnNumbers;
|
||
|
|
set<int>::iterator iter;
|
||
|
|
int drawSize;
|
||
|
|
int nDrawn = 0;
|
||
|
|
int i;
|
||
|
|
int r;
|
||
|
|
bool doInvert;
|
||
|
|
|
||
|
|
result.resize(0);
|
||
|
|
srand(time(0));
|
||
|
|
|
||
|
|
if(((double)setSize) / ((double)subsetSize) <= 2)
|
||
|
|
{
|
||
|
|
doInvert = true;
|
||
|
|
drawSize = setSize - subsetSize;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
doInvert = false;
|
||
|
|
drawSize = subsetSize;
|
||
|
|
}
|
||
|
|
|
||
|
|
while(nDrawn < drawSize)
|
||
|
|
{
|
||
|
|
r = rand();
|
||
|
|
r = r % (setSize + 1);
|
||
|
|
if(r == 0)
|
||
|
|
{
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
if(drawnNumbers.find(r) == drawnNumbers.end())
|
||
|
|
{
|
||
|
|
drawnNumbers.insert(r);
|
||
|
|
++nDrawn;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if(doInvert)
|
||
|
|
{
|
||
|
|
for(i = 1; i <= setSize; ++i)
|
||
|
|
{
|
||
|
|
if(drawnNumbers.find(i) == drawnNumbers.end())
|
||
|
|
{
|
||
|
|
result.push_back(i);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
for(iter = drawnNumbers.begin(); iter != drawnNumbers.end(); ++iter)
|
||
|
|
{
|
||
|
|
result.push_back(*iter);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.1 Type mapping function of operator ~sample~
|
||
|
|
|
||
|
|
A type mapping function takes a nested list as argument. Its contents are
|
||
|
|
type descriptions of an operator's input parameters. A nested list describing
|
||
|
|
the output type of the operator is returned.
|
||
|
|
|
||
|
|
Result type of feed operation.
|
||
|
|
|
||
|
|
---- ((mrel x) int real) -> (stream x)
|
||
|
|
----
|
||
|
|
|
||
|
|
*/
|
||
|
|
static ListExpr CcSampleTypeMap(ListExpr args)
|
||
|
|
{
|
||
|
|
|
||
|
|
if(nl->ListLength(args)!=3){
|
||
|
|
return listutils::typeError("three arguments expected");
|
||
|
|
}
|
||
|
|
|
||
|
|
ListExpr stream = nl->First(args) ;
|
||
|
|
ListExpr minSampleSizeLE = nl->Second(args);
|
||
|
|
ListExpr minSampleRateLE = nl->Third(args);
|
||
|
|
|
||
|
|
if(!listutils::isRelDescription2(stream,CcRel::BasicType()) ||
|
||
|
|
!listutils::isSymbol(minSampleSizeLE,CcInt::BasicType()) ||
|
||
|
|
!listutils::isSymbol(minSampleRateLE,CcReal::BasicType())){
|
||
|
|
return listutils::typeError("mrel x int x real expected");
|
||
|
|
}
|
||
|
|
return nl->Cons(nl->SymbolAtom(Symbol::STREAM()), nl->Rest(stream));
|
||
|
|
}
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.2 Value mapping function of operator ~sample~
|
||
|
|
|
||
|
|
*/
|
||
|
|
struct CcSampleLocalInfo
|
||
|
|
{
|
||
|
|
vector<int> sampleIndices;
|
||
|
|
vector<int>::iterator iter;
|
||
|
|
int lastIndex;
|
||
|
|
CcRelIT* relIT;
|
||
|
|
};
|
||
|
|
|
||
|
|
static int
|
||
|
|
CcSample(Word* args, Word& result, int message, Word& local, Supplier s)
|
||
|
|
{
|
||
|
|
CcSampleLocalInfo* localInfo;
|
||
|
|
CcRel* rel;
|
||
|
|
CcTuple* tuple;
|
||
|
|
|
||
|
|
int sampleSize;
|
||
|
|
int relSize;
|
||
|
|
float sampleRate;
|
||
|
|
int i;
|
||
|
|
int currentIndex;
|
||
|
|
|
||
|
|
switch(message)
|
||
|
|
{
|
||
|
|
case OPEN :
|
||
|
|
localInfo = new CcSampleLocalInfo();
|
||
|
|
local = SetWord(localInfo);
|
||
|
|
|
||
|
|
rel = (CcRel*)args[0].addr;
|
||
|
|
relSize = rel->GetNoTuples();
|
||
|
|
localInfo->relIT = rel->MakeNewScan();
|
||
|
|
sampleSize = ((CcInt*)args[1].addr)->GetIntval();
|
||
|
|
sampleRate = ((CcReal*)args[2].addr)->GetRealval();
|
||
|
|
|
||
|
|
if(sampleSize < 1)
|
||
|
|
{
|
||
|
|
sampleSize = 1;
|
||
|
|
}
|
||
|
|
if(sampleRate <= 0.0)
|
||
|
|
{
|
||
|
|
sampleRate = 0.0;
|
||
|
|
}
|
||
|
|
else if(sampleRate > 1.0)
|
||
|
|
{
|
||
|
|
sampleRate = 1.0;
|
||
|
|
}
|
||
|
|
if((int)(sampleRate * (float)relSize) > sampleSize)
|
||
|
|
{
|
||
|
|
sampleSize = (int)(sampleRate * (float)relSize);
|
||
|
|
}
|
||
|
|
|
||
|
|
if(relSize <= sampleSize)
|
||
|
|
{
|
||
|
|
for(i = 1; i <= relSize; ++i)
|
||
|
|
{
|
||
|
|
localInfo->sampleIndices.push_back(i);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
CcMakeRandomSubset(localInfo->sampleIndices, sampleSize, relSize);
|
||
|
|
}
|
||
|
|
|
||
|
|
localInfo->iter = localInfo->sampleIndices.begin();
|
||
|
|
localInfo->lastIndex = 0;
|
||
|
|
return 0;
|
||
|
|
|
||
|
|
case REQUEST:
|
||
|
|
localInfo = (CcSampleLocalInfo*)local.addr;
|
||
|
|
if(localInfo->iter == localInfo->sampleIndices.end())
|
||
|
|
{
|
||
|
|
return CANCEL;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
currentIndex = *(localInfo->iter);
|
||
|
|
if(!localInfo->relIT->EndOfScan())
|
||
|
|
{
|
||
|
|
tuple = localInfo->relIT->GetTuple();
|
||
|
|
localInfo->relIT->Next();
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
return CANCEL;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Advance iterator to the the next tuple belonging to the sample */
|
||
|
|
for(i = 1; i < currentIndex - localInfo->lastIndex; ++i)
|
||
|
|
{
|
||
|
|
tuple->DeleteIfAllowed();
|
||
|
|
if(!localInfo->relIT->EndOfScan())
|
||
|
|
{
|
||
|
|
tuple = localInfo->relIT->GetTuple();
|
||
|
|
localInfo->relIT->Next();
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
return CANCEL;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
result = SetWord(tuple);
|
||
|
|
localInfo->lastIndex = *(localInfo->iter);
|
||
|
|
localInfo->iter++;
|
||
|
|
return YIELD;
|
||
|
|
}
|
||
|
|
|
||
|
|
case CLOSE :
|
||
|
|
localInfo = (CcSampleLocalInfo*)local.addr;
|
||
|
|
if(localInfo)
|
||
|
|
{
|
||
|
|
delete localInfo->relIT;
|
||
|
|
delete localInfo;
|
||
|
|
local = SetWord(Address(0));
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Specification of operator ~sample~
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string CcSampleSpec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
||
|
|
"\"Example\" ) "
|
||
|
|
"( <text>(mrel x) int real -> (stream x)"
|
||
|
|
"</text--->"
|
||
|
|
"<text>_ sample [ _ , _ ]</text--->"
|
||
|
|
"<text>Produces a random sample of a relation."
|
||
|
|
" The sample size is min(relSize, "
|
||
|
|
"max(s, t * relSize)), where relSize is the size"
|
||
|
|
" of the argument relation, s is the second "
|
||
|
|
"argument, and t the third.</text--->"
|
||
|
|
"<text>query cities sample[0, 0.45] count</text--->"
|
||
|
|
") )";
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Definition of operator ~sample~
|
||
|
|
|
||
|
|
Non-overloaded operators are defined by constructing a new instance of
|
||
|
|
class ~Operator~, passing all operator functions as constructor arguments.
|
||
|
|
|
||
|
|
*/
|
||
|
|
Operator ccrelsample (
|
||
|
|
"sample", // name
|
||
|
|
CcSampleSpec, // specification
|
||
|
|
CcSample, // value mapping
|
||
|
|
Operator::SimpleSelect, // trivial selection function
|
||
|
|
CcSampleTypeMap // type mapping
|
||
|
|
);
|
||
|
|
|
||
|
|
/*
|
||
|
|
4.1 Operator ~consume~
|
||
|
|
|
||
|
|
Collects objects from a stream into a relation.
|
||
|
|
|
||
|
|
4.1.1 Type mapping function of operator ~consume~
|
||
|
|
|
||
|
|
Operator ~consume~ accepts a stream of tuples and returns a relation.
|
||
|
|
|
||
|
|
|
||
|
|
---- (stream x) -> (mrel x)
|
||
|
|
----
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr CcConsumeTypeMap(ListExpr args)
|
||
|
|
{
|
||
|
|
ListExpr first ;
|
||
|
|
|
||
|
|
if(nl->ListLength(args) == 1)
|
||
|
|
{
|
||
|
|
first = nl->First(args);
|
||
|
|
if ((nl->ListLength(first) == 2) &&
|
||
|
|
(CcTypeOfRelAlgSymbol(nl->First(first)) == mstream) &&
|
||
|
|
(nl->ListLength(nl->Second(first)) == 2) &&
|
||
|
|
(CcTypeOfRelAlgSymbol(nl->First(nl->Second(first))) == mtuple))
|
||
|
|
return nl->Cons(nl->SymbolAtom(CcRel::BasicType()), nl->Rest(first));
|
||
|
|
}
|
||
|
|
ErrorReporter::ReportError("Incorrect input for operator consume.");
|
||
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
||
|
|
}
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.2 Value mapping function of operator ~consume~
|
||
|
|
|
||
|
|
*/
|
||
|
|
static int
|
||
|
|
CcConsume(Word* args, Word& result, int message, Word& local, Supplier s)
|
||
|
|
{
|
||
|
|
Word actual;
|
||
|
|
CcRel* rel;
|
||
|
|
|
||
|
|
rel = (CcRel*)((qp->ResultStorage(s)).addr);
|
||
|
|
if( rel->GetNoTuples() > 0 )
|
||
|
|
rel->Empty();
|
||
|
|
|
||
|
|
qp->Open(args[0].addr);
|
||
|
|
qp->Request(args[0].addr, actual);
|
||
|
|
while (qp->Received(args[0].addr))
|
||
|
|
{
|
||
|
|
CcTuple* tuple = (CcTuple*)actual.addr;
|
||
|
|
tuple = tuple->CloneIfNecessary();
|
||
|
|
tuple->SetFree(false);
|
||
|
|
rel->AppendTuple(tuple);
|
||
|
|
qp->Request(args[0].addr, actual);
|
||
|
|
}
|
||
|
|
|
||
|
|
result = SetWord((void*) rel);
|
||
|
|
|
||
|
|
qp->Close(args[0].addr);
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Specification of operator ~consume~
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string CcConsumeSpec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
||
|
|
"\"Example\" ) "
|
||
|
|
"( <text>(stream x) -> (mrel x)</text--->"
|
||
|
|
"<text>_ consume</text--->"
|
||
|
|
"<text>Collects objects from a stream."
|
||
|
|
"</text--->"
|
||
|
|
"<text>query cities feed consume</text--->"
|
||
|
|
") )";
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Definition of operator ~consume~
|
||
|
|
|
||
|
|
*/
|
||
|
|
Operator ccrelconsume (
|
||
|
|
"consume", // name
|
||
|
|
CcConsumeSpec, // specification
|
||
|
|
CcConsume, // value mapping
|
||
|
|
Operator::SimpleSelect, // trivial selection function
|
||
|
|
CcConsumeTypeMap // type mapping
|
||
|
|
);
|
||
|
|
/*
|
||
|
|
|
||
|
|
7.1 Operator ~attr~
|
||
|
|
|
||
|
|
7.1.1 Type mapping function of operator ~attr~
|
||
|
|
|
||
|
|
Result type attr operation.
|
||
|
|
|
||
|
|
----
|
||
|
|
((mtuple ((x1 t1)...(xn tn))) xi) -> ti
|
||
|
|
APPEND (i) ti)
|
||
|
|
----
|
||
|
|
This type mapping uses a special feature of the query processor, in that if
|
||
|
|
requests to append a further argument to the given list of arguments, namely,
|
||
|
|
the index of the attribute within the tuple. This indes is computed within
|
||
|
|
the type mapping function. The request is given through the result expression
|
||
|
|
of the type mapping which has the form, for example,
|
||
|
|
|
||
|
|
----
|
||
|
|
|
||
|
|
(APPEND (1) string)
|
||
|
|
|
||
|
|
----
|
||
|
|
|
||
|
|
The keyword ~APPEND~ occuring as a first element of a returned type expression
|
||
|
|
tells the query processor to add the elements of the following list - the
|
||
|
|
second element of the type expression - as further arguments to the operator
|
||
|
|
(as if they had been written in the query). The third element of the query
|
||
|
|
is then used as the real result type. In this case 1 is the index of the
|
||
|
|
attribute determined in this procedure. The query processor, more precisely
|
||
|
|
the procedure ~anotate~ there, will produce the annotation for the constant 1,
|
||
|
|
append it to the list of annotated arguments, and then use CcString::BasicType() as the
|
||
|
|
result type of the ~attr~ operation.
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr CcAttrTypeMap(ListExpr args)
|
||
|
|
{
|
||
|
|
ListExpr first, second, attrtype;
|
||
|
|
string attrname;
|
||
|
|
int j;
|
||
|
|
if(nl->ListLength(args) == 2)
|
||
|
|
{
|
||
|
|
first = nl->First(args);
|
||
|
|
second = nl->Second(args);
|
||
|
|
|
||
|
|
if((nl->ListLength(first) == 2 ) &&
|
||
|
|
(CcTypeOfRelAlgSymbol(nl->First(first)) == mtuple) &&
|
||
|
|
(nl->IsAtom(second)) &&
|
||
|
|
(nl->AtomType(second) == SymbolType))
|
||
|
|
{
|
||
|
|
attrname = nl->SymbolValue(second);
|
||
|
|
j = CcFindAttribute(nl->Second(first), attrname, attrtype, nl);
|
||
|
|
if (j)
|
||
|
|
return nl->ThreeElemList(nl->SymbolAtom(Symbol::APPEND()),
|
||
|
|
nl->OneElemList(nl->IntAtom(j)), attrtype);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
ErrorReporter::ReportError("Incorrect input for operator attr.");
|
||
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
||
|
|
}
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.2 Value mapping function of operator ~attr~
|
||
|
|
|
||
|
|
The argument vector ~arg~ contains in the first slot ~args[0]~ the tuple
|
||
|
|
and in ~args[2]~ the position of the attribute as a number. Returns as
|
||
|
|
~result~ the value of an attribute at the given position ~args[2]~ in a
|
||
|
|
tuple object. The attribute name is argument 2 in the query and is used
|
||
|
|
in the function ~AttributeTypeMap~ to determine the attribute
|
||
|
|
number ~args[2]~ .
|
||
|
|
|
||
|
|
*/
|
||
|
|
static int
|
||
|
|
CcAttr(Word* args, Word& result, int message, Word& local, Supplier s)
|
||
|
|
{
|
||
|
|
CcTuple* tupleptr;
|
||
|
|
int index;
|
||
|
|
|
||
|
|
tupleptr = (CcTuple*)args[0].addr;
|
||
|
|
index = ((CcInt*)args[2].addr)->GetIntval();
|
||
|
|
assert( 1 <= index && index <= tupleptr->GetNoAttrs() );
|
||
|
|
result = SetWord(tupleptr->Get(index - 1));
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Specification of operator ~attr~
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string CcAttrSpec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
||
|
|
"\"Remarks\" ) "
|
||
|
|
"( <text>((tuple ((x1 t1)...(xn tn))) xi) -> "
|
||
|
|
"ti)</text--->"
|
||
|
|
"<text>attr ( _ , _ )</text--->"
|
||
|
|
"<text>Returns the value of an attribute at a "
|
||
|
|
"given position.</text--->"
|
||
|
|
"<text>not for use with sos-syntax</text--->"
|
||
|
|
") )";
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Definition of operator ~attr~
|
||
|
|
|
||
|
|
*/
|
||
|
|
Operator ccrelattr (
|
||
|
|
"attr", // name
|
||
|
|
CcAttrSpec, // specification
|
||
|
|
CcAttr, // value mapping
|
||
|
|
Operator::SimpleSelect, // trivial selection function
|
||
|
|
CcAttrTypeMap // type mapping
|
||
|
|
);
|
||
|
|
/*
|
||
|
|
|
||
|
|
7.3 Operator ~filter~
|
||
|
|
|
||
|
|
Only tuples, fulfilling a certain condition are passed on to the output stream.
|
||
|
|
|
||
|
|
7.3.1 Type mapping function of operator ~filter~
|
||
|
|
|
||
|
|
Result type of filter operation.
|
||
|
|
|
||
|
|
---- ((stream (mtuple x)) (map (mtuple x) bool)) -> (stream (mtuple x))
|
||
|
|
----
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<bool isFilter>
|
||
|
|
ListExpr
|
||
|
|
CcFilterTypeMap(ListExpr args)
|
||
|
|
{
|
||
|
|
ListExpr first, second;
|
||
|
|
if(nl->ListLength(args) == 2)
|
||
|
|
{
|
||
|
|
first = nl->First(args);
|
||
|
|
second = nl->Second(args);
|
||
|
|
|
||
|
|
if ( (nl->ListLength(first) == 2)
|
||
|
|
&& (nl->ListLength(second) == 3)
|
||
|
|
&& (nl->ListLength(nl->Second(first)) == 2)
|
||
|
|
&& (CcTypeOfRelAlgSymbol(nl->First(nl->Second(first))) == mtuple)
|
||
|
|
&& (CcTypeOfRelAlgSymbol(nl->First(first)) == mstream)
|
||
|
|
&& (CcTypeOfRelAlgSymbol(nl->First(second)) == mmap)
|
||
|
|
&& (CcTypeOfRelAlgSymbol(nl->Third(second)) == mbool)
|
||
|
|
&& (nl->Equal(nl->Second(first),nl->Second(second))))
|
||
|
|
return first;
|
||
|
|
}
|
||
|
|
|
||
|
|
ErrorReporter::ReportError(
|
||
|
|
isFilter ?
|
||
|
|
"Incorrect input for operator filter." :
|
||
|
|
"Incorrect input for operator cancel.");
|
||
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.2 Value mapping function of operator ~filter~
|
||
|
|
|
||
|
|
*/
|
||
|
|
static int
|
||
|
|
CcFilter(Word* args, Word& result, int message, Word& local, Supplier s)
|
||
|
|
{
|
||
|
|
Word elem = SetWord(Address(0));
|
||
|
|
Word funresult = SetWord(Address(0));
|
||
|
|
|
||
|
|
bool found = false;
|
||
|
|
CcTuple* tuple = 0;
|
||
|
|
|
||
|
|
ArgVectorPointer funargs;
|
||
|
|
|
||
|
|
switch ( message )
|
||
|
|
{
|
||
|
|
|
||
|
|
case OPEN:
|
||
|
|
|
||
|
|
//cout << "tfilter OPEN " << endl;
|
||
|
|
|
||
|
|
qp->Open (args[0].addr);
|
||
|
|
return 0;
|
||
|
|
|
||
|
|
case REQUEST:
|
||
|
|
|
||
|
|
//cout << "tfilter REQUEST " << endl;
|
||
|
|
|
||
|
|
funargs = qp->Argument(args[1].addr);
|
||
|
|
qp->Request(args[0].addr, elem);
|
||
|
|
found = false;
|
||
|
|
while (qp->Received(args[0].addr) && !found)
|
||
|
|
{
|
||
|
|
tuple = (CcTuple*)elem.addr;
|
||
|
|
(*funargs)[0] = elem;
|
||
|
|
qp->Request(args[1].addr, funresult);
|
||
|
|
if (((Attribute*)funresult.addr)->IsDefined())
|
||
|
|
{
|
||
|
|
found = ((CcBool*)funresult.addr)->GetBoolval();
|
||
|
|
}
|
||
|
|
if (!found)
|
||
|
|
{
|
||
|
|
tuple->DeleteIfAllowed();
|
||
|
|
qp->Request(args[0].addr, elem);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (found)
|
||
|
|
{
|
||
|
|
result = SetWord(tuple);
|
||
|
|
return YIELD;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
return CANCEL;
|
||
|
|
|
||
|
|
case CLOSE:
|
||
|
|
|
||
|
|
//cout << "tfilter CLOSE " << endl;
|
||
|
|
|
||
|
|
qp->Close(args[0].addr);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Specification of operator ~filter~
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string CcFilterSpec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
||
|
|
"\"Example\" ) "
|
||
|
|
"( <text>((stream x) (map x bool)) -> "
|
||
|
|
"(stream x)</text--->"
|
||
|
|
"<text>_ filter [ fun ]</text--->"
|
||
|
|
"<text>Only tuples, fulfilling a certain "
|
||
|
|
"condition are passed on to the output "
|
||
|
|
"stream.</text--->"
|
||
|
|
"<text>query cities feed filter "
|
||
|
|
"[.population > 500000] consume</text--->"
|
||
|
|
") )";
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Definition of operator ~filter~
|
||
|
|
|
||
|
|
*/
|
||
|
|
Operator ccrelfilter (
|
||
|
|
"filter", // name
|
||
|
|
CcFilterSpec, // specification
|
||
|
|
CcFilter, // value mapping
|
||
|
|
Operator::SimpleSelect, // trivial selection function
|
||
|
|
CcFilterTypeMap<true> // type mapping
|
||
|
|
);
|
||
|
|
/*
|
||
|
|
|
||
|
|
7.3 Operator ~project~
|
||
|
|
|
||
|
|
7.3.1 Type mapping function of operator ~filter~
|
||
|
|
|
||
|
|
Result type of project operation.
|
||
|
|
|
||
|
|
---- ((stream (mtuple ((x1 T1) ... (xn Tn)))) (ai1 ... aik)) ->
|
||
|
|
|
||
|
|
(APPEND
|
||
|
|
(k (i1 ... ik))
|
||
|
|
(stream (mtuple ((ai1 Ti1) ... (aik Tik))))
|
||
|
|
)
|
||
|
|
----
|
||
|
|
|
||
|
|
The type mapping computes the number of attributes and the list of attribute
|
||
|
|
numbers for the given projection attributes and asks the query processor to
|
||
|
|
append it to the given arguments.
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr
|
||
|
|
CcProjectTypeMap(ListExpr args)
|
||
|
|
{
|
||
|
|
bool firstcall = false;
|
||
|
|
int noAttrs = 0, j = 0;
|
||
|
|
|
||
|
|
ListExpr first, second, first2;
|
||
|
|
ListExpr attrtype, newAttrList, lastNewAttrList;
|
||
|
|
ListExpr lastNumberList, numberList, outlist;
|
||
|
|
|
||
|
|
first = second = first2 = nl->TheEmptyList();
|
||
|
|
attrtype = newAttrList = lastNewAttrList = nl->TheEmptyList();
|
||
|
|
lastNumberList = numberList = outlist = nl->TheEmptyList();
|
||
|
|
|
||
|
|
string attrname = "";
|
||
|
|
|
||
|
|
firstcall = true;
|
||
|
|
if (nl->ListLength(args) == 2)
|
||
|
|
{
|
||
|
|
first = nl->First(args);
|
||
|
|
second = nl->Second(args);
|
||
|
|
|
||
|
|
if ((nl->ListLength(first) == 2) &&
|
||
|
|
(CcTypeOfRelAlgSymbol(nl->First(first)) == mstream) &&
|
||
|
|
(nl->ListLength(nl->Second(first)) == 2) &&
|
||
|
|
(CcTypeOfRelAlgSymbol(nl->First(nl->Second(first))) == mtuple) &&
|
||
|
|
(!nl->IsAtom(second)) &&
|
||
|
|
(nl->ListLength(second) > 0))
|
||
|
|
{
|
||
|
|
noAttrs = nl->ListLength(second);
|
||
|
|
while (!(nl->IsEmpty(second)))
|
||
|
|
{
|
||
|
|
first2 = nl->First(second);
|
||
|
|
second = nl->Rest(second);
|
||
|
|
if (nl->AtomType(first2) == SymbolType)
|
||
|
|
{
|
||
|
|
attrname = nl->SymbolValue(first2);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
ErrorReporter::ReportError("Incorrect input for operator project.");
|
||
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
||
|
|
}
|
||
|
|
j = CcFindAttribute(nl->Second(nl->Second(first)),
|
||
|
|
attrname,
|
||
|
|
attrtype,
|
||
|
|
nl);
|
||
|
|
if (j)
|
||
|
|
{
|
||
|
|
if (firstcall)
|
||
|
|
{
|
||
|
|
firstcall = false;
|
||
|
|
newAttrList = nl->OneElemList(nl->TwoElemList(first2, attrtype));
|
||
|
|
lastNewAttrList = newAttrList;
|
||
|
|
numberList = nl->OneElemList(nl->IntAtom(j));
|
||
|
|
lastNumberList = numberList;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
lastNewAttrList =
|
||
|
|
nl->Append(lastNewAttrList, nl->TwoElemList(first2, attrtype));
|
||
|
|
lastNumberList =
|
||
|
|
nl->Append(lastNumberList, nl->IntAtom(j));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
ErrorReporter::ReportError("Incorrect input for operator project.");
|
||
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
// Check whether all new attribute names are distinct
|
||
|
|
// - not yet implemented
|
||
|
|
outlist = nl->ThreeElemList(
|
||
|
|
nl->SymbolAtom(Symbol::APPEND()),
|
||
|
|
nl->TwoElemList(nl->IntAtom(noAttrs), numberList),
|
||
|
|
nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()),
|
||
|
|
nl->TwoElemList(
|
||
|
|
nl->SymbolAtom(CcTuple::BasicType()),
|
||
|
|
newAttrList)));
|
||
|
|
// cout << nl->WriteToFile("/dev/tty",outlist) << endl;
|
||
|
|
return outlist;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
ErrorReporter::ReportError("Incorrect input for operator project.");
|
||
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
||
|
|
}
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.2 Value mapping function of operator ~project~
|
||
|
|
|
||
|
|
*/
|
||
|
|
static int
|
||
|
|
CcProject(Word* args, Word& result, int message, Word& local, Supplier s)
|
||
|
|
{
|
||
|
|
Word elem1, elem2;
|
||
|
|
int noOfAttrs, index;
|
||
|
|
Supplier son;
|
||
|
|
Attribute* attr;
|
||
|
|
CcTuple* t;
|
||
|
|
|
||
|
|
|
||
|
|
switch (message)
|
||
|
|
{
|
||
|
|
case OPEN :
|
||
|
|
|
||
|
|
//cout << "project OPEN" << endl;
|
||
|
|
|
||
|
|
|
||
|
|
qp->Open(args[0].addr);
|
||
|
|
return 0;
|
||
|
|
|
||
|
|
case REQUEST :
|
||
|
|
|
||
|
|
//cout << "project REQUEST" << endl;
|
||
|
|
|
||
|
|
qp->Request(args[0].addr, elem1);
|
||
|
|
if (qp->Received(args[0].addr))
|
||
|
|
{
|
||
|
|
t = new CcTuple();
|
||
|
|
t->SetFree(true);
|
||
|
|
|
||
|
|
noOfAttrs = ((CcInt*)args[2].addr)->GetIntval();
|
||
|
|
t->SetNoAttrs(noOfAttrs);
|
||
|
|
for (int i=1; i <= noOfAttrs; i++)
|
||
|
|
{
|
||
|
|
son = qp->GetSupplier(args[3].addr, i-1);
|
||
|
|
qp->Request(son, elem2);
|
||
|
|
index = ((CcInt*)elem2.addr)->GetIntval();
|
||
|
|
attr = ((CcTuple*)elem1.addr)->Get(index-1);
|
||
|
|
t->Put(i-1, ((Attribute*)attr->Clone()));
|
||
|
|
}
|
||
|
|
((CcTuple*)elem1.addr)->DeleteIfAllowed();
|
||
|
|
result = SetWord(t);
|
||
|
|
return YIELD;
|
||
|
|
}
|
||
|
|
else return CANCEL;
|
||
|
|
|
||
|
|
case CLOSE :
|
||
|
|
|
||
|
|
//cout << "project CLOSE" << endl;
|
||
|
|
|
||
|
|
qp->Close(args[0].addr);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Specification of operator ~project~
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string CcProjectSpec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
||
|
|
"\"Example\" ) "
|
||
|
|
"( <text>((stream (mtuple ((x1 T1) ... "
|
||
|
|
"(xn Tn)))) (ai1 ... aik)) -> (stream (mtuple"
|
||
|
|
" ((ai1 Ti1) ... (aik Tik))))</text--->"
|
||
|
|
"<text>_ project [ list ]</text--->"
|
||
|
|
"<text>Produces a projection tuple for each "
|
||
|
|
"tuple of its input stream.</text--->"
|
||
|
|
"<text>query cities feed project[cityname, "
|
||
|
|
"population] consume</text--->"
|
||
|
|
") )";
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Definition of operator ~project~
|
||
|
|
|
||
|
|
*/
|
||
|
|
Operator ccrelproject (
|
||
|
|
"project", // name
|
||
|
|
CcProjectSpec, // specification
|
||
|
|
CcProject, // value mapping
|
||
|
|
Operator::SimpleSelect, // trivial selection function
|
||
|
|
CcProjectTypeMap // type mapping
|
||
|
|
);
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
7.3 Operator ~remove~
|
||
|
|
|
||
|
|
7.3.1 Type mapping function of operator ~remove~
|
||
|
|
|
||
|
|
Result type of ~remove~ operation.
|
||
|
|
|
||
|
|
---- ((stream (mtuple ((x1 T1) ... (xn Tn)))) (ai1 ... aik)) ->
|
||
|
|
|
||
|
|
(APPEND
|
||
|
|
(n-k (j1 ... jn-k))
|
||
|
|
(stream (mtuple ((aj1 Tj1) ... (ajn-k Tjn-k))))
|
||
|
|
)
|
||
|
|
----
|
||
|
|
|
||
|
|
The type mapping computes the number of attributes and the list of attribute
|
||
|
|
numbers for the given left attributes (after removal) and asks the query processor to
|
||
|
|
append it to the given arguments.
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr
|
||
|
|
CcRemoveTypeMap(ListExpr args)
|
||
|
|
{
|
||
|
|
bool firstcall = false;
|
||
|
|
int noAttrs = 0, j = 0;
|
||
|
|
|
||
|
|
ListExpr first, second, first2;
|
||
|
|
ListExpr attrtype, newAttrList, lastNewAttrList;
|
||
|
|
ListExpr lastNumberList, numberList, outlist;
|
||
|
|
|
||
|
|
first = second = first2 = nl->TheEmptyList();
|
||
|
|
attrtype = newAttrList = lastNewAttrList = nl->TheEmptyList();
|
||
|
|
lastNumberList = numberList = outlist = nl->TheEmptyList();
|
||
|
|
|
||
|
|
string attrname = "";
|
||
|
|
set<int> removeSet;
|
||
|
|
removeSet.clear();
|
||
|
|
|
||
|
|
firstcall = true;
|
||
|
|
if (nl->ListLength(args) == 2)
|
||
|
|
{
|
||
|
|
first = nl->First(args);
|
||
|
|
second = nl->Second(args);
|
||
|
|
|
||
|
|
if ((nl->ListLength(first) == 2) &&
|
||
|
|
(CcTypeOfRelAlgSymbol(nl->First(first)) == mstream) &&
|
||
|
|
(nl->ListLength(nl->Second(first)) == 2) &&
|
||
|
|
(CcTypeOfRelAlgSymbol(nl->First(nl->Second(first))) == mtuple) &&
|
||
|
|
(!nl->IsAtom(second)) &&
|
||
|
|
(nl->ListLength(second) > 0))
|
||
|
|
{
|
||
|
|
while (!(nl->IsEmpty(second)))
|
||
|
|
{
|
||
|
|
first2 = nl->First(second);
|
||
|
|
second = nl->Rest(second);
|
||
|
|
|
||
|
|
if (nl->AtomType(first2) == SymbolType)
|
||
|
|
{
|
||
|
|
attrname = nl->SymbolValue(first2);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
ErrorReporter::ReportError("Incorrect input for operator ~remove~.");
|
||
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
||
|
|
}
|
||
|
|
|
||
|
|
j = CcFindAttribute(nl->Second(nl->Second(first)), attrname,
|
||
|
|
attrtype, nl);
|
||
|
|
if (j) removeSet.insert(j);
|
||
|
|
else
|
||
|
|
{
|
||
|
|
ErrorReporter::ReportError("Incorrect input for operator ~remove~.");
|
||
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
/* here we need to generate new attr list according to removeSet */
|
||
|
|
ListExpr oldAttrList;
|
||
|
|
int i;
|
||
|
|
i=0; // i is the index of the old attriblist
|
||
|
|
first = nl->First(args);
|
||
|
|
second = nl->Second(args);
|
||
|
|
oldAttrList=nl->Second(nl->Second(first));
|
||
|
|
//noAttrs = nl->ListLength(oldAttrList) - nl->ListLength(second); // n-k
|
||
|
|
noAttrs =0;
|
||
|
|
while (!(nl->IsEmpty(oldAttrList)))
|
||
|
|
{
|
||
|
|
i++;
|
||
|
|
first2 = nl->First(oldAttrList);
|
||
|
|
oldAttrList = nl->Rest(oldAttrList);
|
||
|
|
|
||
|
|
if (removeSet.find(i)==removeSet.end())
|
||
|
|
//the attribute is not in the removal list
|
||
|
|
{
|
||
|
|
noAttrs++;
|
||
|
|
if (firstcall)
|
||
|
|
{
|
||
|
|
firstcall = false;
|
||
|
|
newAttrList = nl->OneElemList(first2);
|
||
|
|
lastNewAttrList = newAttrList;
|
||
|
|
numberList = nl->OneElemList(nl->IntAtom(i));
|
||
|
|
lastNumberList = numberList;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
lastNewAttrList = nl->Append(lastNewAttrList, first2);
|
||
|
|
lastNumberList = nl->Append(lastNumberList, nl->IntAtom(i));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Check whether all new attribute names are distinct
|
||
|
|
// - not yet implemented
|
||
|
|
//check whether the returning list is null
|
||
|
|
if (noAttrs>0)
|
||
|
|
{outlist = nl->ThreeElemList(
|
||
|
|
nl->SymbolAtom(Symbol::APPEND()),
|
||
|
|
nl->TwoElemList(nl->IntAtom(noAttrs), numberList),
|
||
|
|
nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()),
|
||
|
|
nl->TwoElemList(nl->SymbolAtom(
|
||
|
|
CcTuple::BasicType()),
|
||
|
|
newAttrList)));
|
||
|
|
return outlist;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
ErrorReporter::ReportError(
|
||
|
|
"Incorrect input for operator ~remove~ - "
|
||
|
|
"trying to remove all attributes.");
|
||
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
ErrorReporter::ReportError("Incorrect input for operator ~remove~.");
|
||
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.2 Value mapping function of operator ~remove~
|
||
|
|
|
||
|
|
*/
|
||
|
|
static int
|
||
|
|
CcRemove(Word* args, Word& result, int message, Word& local, Supplier s)
|
||
|
|
{
|
||
|
|
Word elem1, elem2;
|
||
|
|
int noOfAttrs, index;
|
||
|
|
Supplier son;
|
||
|
|
Attribute* attr;
|
||
|
|
CcTuple* t;
|
||
|
|
|
||
|
|
|
||
|
|
switch (message)
|
||
|
|
{
|
||
|
|
case OPEN :
|
||
|
|
qp->Open(args[0].addr);
|
||
|
|
return 0;
|
||
|
|
|
||
|
|
case REQUEST :
|
||
|
|
qp->Request(args[0].addr, elem1);
|
||
|
|
if (qp->Received(args[0].addr))
|
||
|
|
{
|
||
|
|
t = new CcTuple();
|
||
|
|
t->SetFree(true);
|
||
|
|
|
||
|
|
noOfAttrs = ((CcInt*)args[2].addr)->GetIntval();
|
||
|
|
t->SetNoAttrs(noOfAttrs);
|
||
|
|
for (int i=1; i <= noOfAttrs; i++)
|
||
|
|
{
|
||
|
|
son = qp->GetSupplier(args[3].addr, i-1);
|
||
|
|
qp->Request(son, elem2);
|
||
|
|
index = ((CcInt*)elem2.addr)->GetIntval();
|
||
|
|
attr = ((CcTuple*)elem1.addr)->Get(index-1);
|
||
|
|
t->Put(i-1, ((Attribute*)attr->Clone()));
|
||
|
|
}
|
||
|
|
((CcTuple*)elem1.addr)->DeleteIfAllowed();
|
||
|
|
result = SetWord(t);
|
||
|
|
return YIELD;
|
||
|
|
}
|
||
|
|
else return CANCEL;
|
||
|
|
|
||
|
|
case CLOSE :
|
||
|
|
qp->Close(args[0].addr);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Specification of operator ~remove~
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string CcRemoveSpec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
||
|
|
"\"Example\" ) "
|
||
|
|
"( <text>((stream (mtuple ((x1 T1) ... "
|
||
|
|
"(xn Tn)))) (ai1 ... aik)) -> (stream "
|
||
|
|
"(mtuple ((aj1 Tj1) ... (ajn-k Tjn-k))))"
|
||
|
|
"</text--->"
|
||
|
|
"<text>_ remove [list]</text--->"
|
||
|
|
"<text>Produces a removal tuple for each "
|
||
|
|
"tuple of its input stream.</text--->"
|
||
|
|
"<text>query cities feed remove[zipcode] "
|
||
|
|
"consume</text--->"
|
||
|
|
") )";
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Definition of operator ~remove~
|
||
|
|
|
||
|
|
*/
|
||
|
|
Operator ccrelremove (
|
||
|
|
"remove", // name
|
||
|
|
CcRemoveSpec, // specification
|
||
|
|
CcRemove, // value mapping
|
||
|
|
Operator::SimpleSelect, // trivial selection function
|
||
|
|
CcRemoveTypeMap // type mapping
|
||
|
|
);
|
||
|
|
/*
|
||
|
|
|
||
|
|
7.3 Operator ~product~
|
||
|
|
|
||
|
|
5.6.1 Help Function ~Concat~
|
||
|
|
|
||
|
|
Copies the attribute values of two tuples
|
||
|
|
(words) ~r~ and ~s~ into tuple (word) ~t~.
|
||
|
|
|
||
|
|
*/
|
||
|
|
void CcConcat (Word r, Word s, Word& t)
|
||
|
|
{
|
||
|
|
int rnoattrs, snoattrs, tnoattrs;
|
||
|
|
Attribute* attr;
|
||
|
|
|
||
|
|
rnoattrs = ((CcTuple*)r.addr)->GetNoAttrs();
|
||
|
|
snoattrs = ((CcTuple*)s.addr)->GetNoAttrs();
|
||
|
|
if ((rnoattrs + snoattrs) > MaxSizeOfAttr)
|
||
|
|
{
|
||
|
|
tnoattrs = MaxSizeOfAttr;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
tnoattrs = rnoattrs + snoattrs;
|
||
|
|
}
|
||
|
|
|
||
|
|
((CcTuple*)t.addr)->SetNoAttrs(tnoattrs);
|
||
|
|
for (int i = 1; i <= rnoattrs; i++)
|
||
|
|
{
|
||
|
|
attr = ((CcTuple*)r.addr)->Get(i - 1);
|
||
|
|
((CcTuple*)t.addr)->Put((i - 1), ((Attribute*)attr)->Clone());
|
||
|
|
}
|
||
|
|
for (int j = (rnoattrs + 1); j <= tnoattrs; j++)
|
||
|
|
{
|
||
|
|
attr = ((CcTuple*)s.addr)->Get(j - rnoattrs - 1);
|
||
|
|
((CcTuple*)t.addr)->Put((j - 1), ((Attribute*)attr)->Clone());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
/*
|
||
|
|
|
||
|
|
7.3.1 Type mapping function of operator ~product~
|
||
|
|
|
||
|
|
Result type of product operation.
|
||
|
|
|
||
|
|
---- ((stream (mtuple (x1 ... xn))) (stream (mtuple (y1 ... ym))))
|
||
|
|
|
||
|
|
-> (stream (mtuple (x1 ... xn y1 ... ym)))
|
||
|
|
----
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
bool CcCompareNames(ListExpr list)
|
||
|
|
{
|
||
|
|
vector<string> attrnamestrlist;
|
||
|
|
vector<string>::iterator it;
|
||
|
|
ListExpr attrnamelist;
|
||
|
|
int unique;
|
||
|
|
string attrname;
|
||
|
|
|
||
|
|
attrnamelist = list;
|
||
|
|
attrnamestrlist.resize(nl->ListLength(list));
|
||
|
|
it = attrnamestrlist.begin();
|
||
|
|
while (!nl->IsEmpty(attrnamelist))
|
||
|
|
{
|
||
|
|
attrname = nl->SymbolValue(nl->First(nl->First(attrnamelist)));
|
||
|
|
attrnamelist = nl->Rest(attrnamelist);
|
||
|
|
unique = std::count(attrnamestrlist.begin(),
|
||
|
|
attrnamestrlist.end(),
|
||
|
|
attrname);
|
||
|
|
*it = attrname;
|
||
|
|
if (unique) return false;
|
||
|
|
it++;
|
||
|
|
}
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
ListExpr
|
||
|
|
CcProductTypeMap(ListExpr args)
|
||
|
|
{
|
||
|
|
ListExpr first, second, list, list1, list2, outlist;
|
||
|
|
|
||
|
|
if (nl->ListLength(args) == 2)
|
||
|
|
{
|
||
|
|
first = nl->First(args); second = nl->Second(args);
|
||
|
|
|
||
|
|
// Check first argument and extract list1
|
||
|
|
if (nl->ListLength(first) == 2)
|
||
|
|
{
|
||
|
|
if (CcTypeOfRelAlgSymbol(nl->First(first)) == mstream)
|
||
|
|
{
|
||
|
|
if (nl->ListLength(nl->Second(first)) == 2)
|
||
|
|
{
|
||
|
|
if (CcTypeOfRelAlgSymbol(nl->First(nl->Second(first))) == mtuple)
|
||
|
|
{
|
||
|
|
list1 = nl->Second(nl->Second(first));
|
||
|
|
}
|
||
|
|
else goto typeerror;
|
||
|
|
}
|
||
|
|
else goto typeerror;
|
||
|
|
}
|
||
|
|
else goto typeerror;
|
||
|
|
}
|
||
|
|
else goto typeerror;
|
||
|
|
|
||
|
|
// Check second argument and extract list2
|
||
|
|
if (nl->ListLength(second) == 2)
|
||
|
|
{
|
||
|
|
if (CcTypeOfRelAlgSymbol(nl->First(second)) == mstream)
|
||
|
|
{
|
||
|
|
if (nl->ListLength(nl->Second(second)) == 2)
|
||
|
|
{
|
||
|
|
if (CcTypeOfRelAlgSymbol(nl->First(nl->Second(second))) == mtuple)
|
||
|
|
{
|
||
|
|
list2 = nl->Second(nl->Second(second));
|
||
|
|
}
|
||
|
|
else goto typeerror;
|
||
|
|
}
|
||
|
|
else goto typeerror;
|
||
|
|
}
|
||
|
|
else goto typeerror;
|
||
|
|
}
|
||
|
|
else goto typeerror;
|
||
|
|
|
||
|
|
list = CcConcatLists(list1, list2);
|
||
|
|
// Check whether all new attribute names are distinct
|
||
|
|
// - not yet implemented
|
||
|
|
|
||
|
|
if ( CcCompareNames(list) )
|
||
|
|
{
|
||
|
|
outlist = nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()),
|
||
|
|
nl->TwoElemList(nl->SymbolAtom(CcTuple::BasicType()), list));
|
||
|
|
return outlist;
|
||
|
|
}
|
||
|
|
else goto typeerror;
|
||
|
|
}
|
||
|
|
else goto typeerror;
|
||
|
|
|
||
|
|
typeerror:
|
||
|
|
ErrorReporter::ReportError("Incorrect input for operator product.");
|
||
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
||
|
|
}
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.2 Value mapping function of operator ~product~
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
CPUTimeMeasurer ccProductMeasurer;
|
||
|
|
|
||
|
|
struct CcProductLocalInfo
|
||
|
|
{
|
||
|
|
CcTuple* currentTuple;
|
||
|
|
CcRep rightRel;
|
||
|
|
CcRep::iterator iter;
|
||
|
|
};
|
||
|
|
|
||
|
|
static int
|
||
|
|
CcProduct(Word* args, Word& result, int message, Word& local, Supplier s)
|
||
|
|
{
|
||
|
|
Word r, u, t;
|
||
|
|
CcTuple* tuple;
|
||
|
|
CcProductLocalInfo* pli;
|
||
|
|
|
||
|
|
switch (message)
|
||
|
|
{
|
||
|
|
case OPEN :
|
||
|
|
|
||
|
|
qp->Open(args[0].addr);
|
||
|
|
qp->Request(args[0].addr, r);
|
||
|
|
pli = new CcProductLocalInfo;
|
||
|
|
pli->currentTuple = qp->Received(args[0].addr) ? (CcTuple*)r.addr : 0;
|
||
|
|
|
||
|
|
/* materialize right stream */
|
||
|
|
qp->Open(args[1].addr);
|
||
|
|
qp->Request(args[1].addr, u);
|
||
|
|
while(qp->Received(args[1].addr))
|
||
|
|
{
|
||
|
|
pli->rightRel.push_back((CcTuple*)u.addr);
|
||
|
|
qp->Request(args[1].addr, u);
|
||
|
|
}
|
||
|
|
|
||
|
|
pli->iter = pli->rightRel.begin();
|
||
|
|
local = SetWord(pli);
|
||
|
|
return 0;
|
||
|
|
|
||
|
|
case REQUEST :
|
||
|
|
pli = (CcProductLocalInfo*)local.addr;
|
||
|
|
|
||
|
|
ccProductMeasurer.Enter();
|
||
|
|
|
||
|
|
if (pli->currentTuple == 0)
|
||
|
|
{
|
||
|
|
ccProductMeasurer.Exit();
|
||
|
|
return CANCEL;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
if(pli->iter != pli->rightRel.end())
|
||
|
|
{
|
||
|
|
tuple = new CcTuple();
|
||
|
|
tuple->SetFree(true);
|
||
|
|
t = SetWord(tuple);
|
||
|
|
CcConcat(SetWord(pli->currentTuple), SetWord(*(pli->iter)), t);
|
||
|
|
result = t;
|
||
|
|
++(pli->iter);
|
||
|
|
|
||
|
|
ccProductMeasurer.Exit();
|
||
|
|
return YIELD;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
/* restart iterator for right relation and
|
||
|
|
fetch a new tuple from left stream */
|
||
|
|
pli->currentTuple->DeleteIfAllowed();
|
||
|
|
pli->currentTuple = 0;
|
||
|
|
qp->Request(args[0].addr, r);
|
||
|
|
if (qp->Received(args[0].addr))
|
||
|
|
{
|
||
|
|
pli->currentTuple = (CcTuple*)r.addr;
|
||
|
|
pli->iter = pli->rightRel.begin();
|
||
|
|
if(pli->iter == pli->rightRel.end()) // second stream is empty
|
||
|
|
{
|
||
|
|
ccProductMeasurer.Exit();
|
||
|
|
return CANCEL;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
tuple = new CcTuple();
|
||
|
|
tuple->SetFree(true);
|
||
|
|
t = SetWord(tuple);
|
||
|
|
CcConcat(SetWord(pli->currentTuple), SetWord(*(pli->iter)), t);
|
||
|
|
result = t;
|
||
|
|
++(pli->iter);
|
||
|
|
|
||
|
|
ccProductMeasurer.Exit();
|
||
|
|
return YIELD;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
ccProductMeasurer.Exit();
|
||
|
|
return CANCEL; // left stream exhausted
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
case CLOSE :
|
||
|
|
pli = (CcProductLocalInfo*)local.addr;
|
||
|
|
if(pli)
|
||
|
|
{
|
||
|
|
if(pli->currentTuple != 0)
|
||
|
|
{
|
||
|
|
pli->currentTuple->DeleteIfAllowed();
|
||
|
|
}
|
||
|
|
|
||
|
|
for(pli->iter = pli->rightRel.begin();
|
||
|
|
pli->iter != pli->rightRel.end();
|
||
|
|
++(pli->iter))
|
||
|
|
{
|
||
|
|
(*(pli->iter))->DeleteIfAllowed();
|
||
|
|
}
|
||
|
|
delete pli;
|
||
|
|
local = SetWord(Address(0));
|
||
|
|
}
|
||
|
|
qp->Close(args[0].addr);
|
||
|
|
qp->Close(args[1].addr);
|
||
|
|
|
||
|
|
ccProductMeasurer.PrintCPUTimeAndReset("Product CPU Time : ");
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Specification of operator ~product~
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string CcProductSpec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
||
|
|
"\"Example\" ) "
|
||
|
|
"( <text>((stream (mtuple (x1 ... xn))) (stream "
|
||
|
|
"(mtuple (y1 ... ym)))) -> (stream (mtuple (x1 "
|
||
|
|
"... xn y1 ... ym)))</text--->"
|
||
|
|
"<text>_ _ product</text--->"
|
||
|
|
"<text>Computes a Cartesian product stream from "
|
||
|
|
"its two argument streams.</text--->"
|
||
|
|
"<text>query ten feed twenty feed product count"
|
||
|
|
"</text--->"
|
||
|
|
" ) )";
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Definition of operator ~product~
|
||
|
|
|
||
|
|
*/
|
||
|
|
Operator ccrelproduct (
|
||
|
|
"product", // name
|
||
|
|
CcProductSpec, // specification
|
||
|
|
CcProduct, // value mapping
|
||
|
|
Operator::SimpleSelect, // trivial selection function
|
||
|
|
CcProductTypeMap // type mapping
|
||
|
|
);
|
||
|
|
/*
|
||
|
|
|
||
|
|
7.3 Operator ~cancel~
|
||
|
|
|
||
|
|
Transmits tuple from its input stream to its output stream until a tuple
|
||
|
|
arrives fulfilling some condition.
|
||
|
|
|
||
|
|
7.3.1 Type mapping function of operator ~cancel~
|
||
|
|
|
||
|
|
Type mapping for ~cancel~ is the same, as type mapping for operator ~filter~.
|
||
|
|
Result type of cancel operation.
|
||
|
|
|
||
|
|
---- ((stream x) (map x bool)) -> (stream x)
|
||
|
|
----
|
||
|
|
|
||
|
|
4.1.2 Value mapping function of operator ~cancel~
|
||
|
|
|
||
|
|
*/
|
||
|
|
static int
|
||
|
|
CcCancel(Word* args, Word& result, int message, Word& local, Supplier s)
|
||
|
|
{
|
||
|
|
Word t, value;
|
||
|
|
CcTuple* tuple;
|
||
|
|
bool found;
|
||
|
|
ArgVectorPointer vector;
|
||
|
|
|
||
|
|
switch (message)
|
||
|
|
{
|
||
|
|
case OPEN :
|
||
|
|
|
||
|
|
qp->Open(args[0].addr);
|
||
|
|
return 0;
|
||
|
|
|
||
|
|
case REQUEST :
|
||
|
|
|
||
|
|
qp->Request(args[0].addr, t);
|
||
|
|
found= false;
|
||
|
|
if (qp->Received(args[0].addr))
|
||
|
|
{
|
||
|
|
tuple = (CcTuple*)t.addr;
|
||
|
|
vector = qp->Argument(args[1].addr);
|
||
|
|
(*vector)[0] = t;
|
||
|
|
qp->Request(args[1].addr, value);
|
||
|
|
found =
|
||
|
|
((CcBool*)value.addr)->IsDefined()
|
||
|
|
&& ((CcBool*)value.addr)->GetBoolval();
|
||
|
|
if (found)
|
||
|
|
{
|
||
|
|
qp->Close(args[0].addr);
|
||
|
|
return CANCEL;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
result = SetWord(tuple);
|
||
|
|
return YIELD;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else return CANCEL;
|
||
|
|
|
||
|
|
case CLOSE :
|
||
|
|
|
||
|
|
qp->Close(args[0].addr);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Specification of operator ~cancel~
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string CcCancelSpec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
||
|
|
"\"Example\" ) "
|
||
|
|
"( <text>((stream x) (map x bool)) -> "
|
||
|
|
"(stream x)</text--->"
|
||
|
|
"<text>_ cancel [ fun ]</text--->"
|
||
|
|
"<text>Transmits tuple from its input stream "
|
||
|
|
"to its output stream until a tuple arrives "
|
||
|
|
"fulfilling some condition.</text--->"
|
||
|
|
"<text>query cities feed cancel [.cityname = "
|
||
|
|
"\"Dortmund\"] consume</text--->"
|
||
|
|
") )";
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Definition of operator ~cancel~
|
||
|
|
|
||
|
|
*/
|
||
|
|
Operator ccrelcancel (
|
||
|
|
"cancel", // name
|
||
|
|
CcCancelSpec, // specification
|
||
|
|
CcCancel, // value mapping
|
||
|
|
Operator::SimpleSelect, // trivial selection function
|
||
|
|
CcFilterTypeMap<false> // type mapping
|
||
|
|
);
|
||
|
|
/*
|
||
|
|
|
||
|
|
7.3 Operator ~count~
|
||
|
|
|
||
|
|
Count the number of tuples within a stream of tuples.
|
||
|
|
|
||
|
|
|
||
|
|
7.3.1 Type mapping function of operator ~count~
|
||
|
|
|
||
|
|
Operator ~count~ accepts a stream of tuples and returns an integer.
|
||
|
|
|
||
|
|
---- (stream (mtuple x)) -> int
|
||
|
|
----
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr
|
||
|
|
CcCountTypeMap(ListExpr args)
|
||
|
|
{
|
||
|
|
ListExpr first;
|
||
|
|
|
||
|
|
if( nl->ListLength(args) == 1 )
|
||
|
|
{
|
||
|
|
first = nl->First(args);
|
||
|
|
if ( (nl->ListLength(first) == 2) &&
|
||
|
|
nl->ListLength(nl->Second(first)) == 2 )
|
||
|
|
{
|
||
|
|
if ( ( CcTypeOfRelAlgSymbol(nl->First(first)) == mstream
|
||
|
|
|| CcTypeOfRelAlgSymbol(nl->First(first)) == mrel )
|
||
|
|
&& CcTypeOfRelAlgSymbol(nl->First(nl->Second(first))) == mtuple )
|
||
|
|
return nl->SymbolAtom(CcInt::BasicType());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
ErrorReporter::ReportError("Incorrect input for operator count.");
|
||
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.2 Value mapping functions of operator ~count~
|
||
|
|
|
||
|
|
*/
|
||
|
|
static int
|
||
|
|
CcCountStream(Word* args, Word& result, int message, Word& local, Supplier s)
|
||
|
|
{
|
||
|
|
Word elem;
|
||
|
|
int count = 0;
|
||
|
|
|
||
|
|
//cout << "tcount" << endl;
|
||
|
|
|
||
|
|
qp->Open(args[0].addr);
|
||
|
|
qp->Request(args[0].addr, elem);
|
||
|
|
while ( qp->Received(args[0].addr) )
|
||
|
|
{
|
||
|
|
((CcTuple*)elem.addr)->DeleteIfAllowed();
|
||
|
|
count++;
|
||
|
|
qp->Request(args[0].addr, elem);
|
||
|
|
}
|
||
|
|
result = qp->ResultStorage(s);
|
||
|
|
((CcInt*) result.addr)->Set(true, count);
|
||
|
|
qp->Close(args[0].addr);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int
|
||
|
|
CcCountRel(Word* args, Word& result, int message, Word& local, Supplier s)
|
||
|
|
{
|
||
|
|
CcRel* rel = (CcRel*)args[0].addr;
|
||
|
|
result = qp->ResultStorage(s);
|
||
|
|
((CcInt*) result.addr)->Set(true, rel->GetNoTuples());
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Specification of operator ~count~
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string CcCountSpec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
||
|
|
"\"Example\" ) "
|
||
|
|
"( <text>((stream/mrel (mtuple x))) -> int"
|
||
|
|
"</text--->"
|
||
|
|
"<text>_ count</text--->"
|
||
|
|
"<text>Count number of tuples within a stream "
|
||
|
|
"or a relation of tuples.</text--->"
|
||
|
|
"<text>query cities count or query cities "
|
||
|
|
"feed count</text--->"
|
||
|
|
") )";
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.3.1 Selection function of operator ~tcount~
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
static int
|
||
|
|
CcCountSelect( ListExpr args )
|
||
|
|
{
|
||
|
|
if(nl->ListLength(args) == 1)
|
||
|
|
{
|
||
|
|
ListExpr first = nl->First(args);
|
||
|
|
if(nl->ListLength(first) == 2)
|
||
|
|
{
|
||
|
|
if (CcTypeOfRelAlgSymbol(nl->First(first)) == mstream)
|
||
|
|
{
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
if(CcTypeOfRelAlgSymbol(nl->First(first)) == mrel)
|
||
|
|
{
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Definition of operator ~count~
|
||
|
|
|
||
|
|
*/
|
||
|
|
ValueMapping ccrelcountmap[] = {CcCountStream, CcCountRel };
|
||
|
|
|
||
|
|
Operator ccrelcount (
|
||
|
|
"count", // name
|
||
|
|
CcCountSpec, // specification
|
||
|
|
2, // number of value mapping functions
|
||
|
|
ccrelcountmap, // value mapping functions
|
||
|
|
CcCountSelect, // trivial selection function
|
||
|
|
CcCountTypeMap // type mapping
|
||
|
|
);
|
||
|
|
/*
|
||
|
|
|
||
|
|
7.3 Operator ~rename~
|
||
|
|
|
||
|
|
Renames all attribute names by adding them with the postfix passed as parameter.
|
||
|
|
|
||
|
|
7.3.1 Type mapping function of operator ~rename~
|
||
|
|
|
||
|
|
Type mapping for ~rename~ is
|
||
|
|
|
||
|
|
---- ((stream (mtuple([a1:d1, ... ,an:dn)))ar) ->
|
||
|
|
(stream (mtuple([a1ar:d1, ... ,anar:dn)))
|
||
|
|
----
|
||
|
|
|
||
|
|
*/
|
||
|
|
static ListExpr
|
||
|
|
CcRenameTypeMap( ListExpr args )
|
||
|
|
{
|
||
|
|
ListExpr first, first2, second;
|
||
|
|
ListExpr rest, listn, lastlistn;
|
||
|
|
|
||
|
|
first = first2 = second = nl->TheEmptyList();
|
||
|
|
rest = listn = lastlistn = nl->TheEmptyList();
|
||
|
|
|
||
|
|
string attrname = "";
|
||
|
|
string attrnamen = "";
|
||
|
|
bool firstcall = true;
|
||
|
|
|
||
|
|
if(nl->ListLength(args) == 2)
|
||
|
|
{
|
||
|
|
first = nl->First(args);
|
||
|
|
second = nl->Second(args);
|
||
|
|
|
||
|
|
if((nl->ListLength(first) == 2 ) &&
|
||
|
|
(CcTypeOfRelAlgSymbol(nl->First(first)) == mstream) &&
|
||
|
|
(CcTypeOfRelAlgSymbol(nl->First(nl->Second(first))) == mtuple) &&
|
||
|
|
nl->IsAtom(second) &&
|
||
|
|
(nl->AtomType(second) == SymbolType))
|
||
|
|
{
|
||
|
|
rest = nl->Second(nl->Second(first));
|
||
|
|
while (!(nl->IsEmpty(rest)))
|
||
|
|
{
|
||
|
|
first2 = nl->First(rest);
|
||
|
|
rest = nl->Rest(rest);
|
||
|
|
nl->SymbolValue(nl->First(first));
|
||
|
|
attrname = nl->SymbolValue(nl->First(first2));
|
||
|
|
attrnamen = nl->SymbolValue(second);
|
||
|
|
attrname.append("_");
|
||
|
|
attrname.append(attrnamen);
|
||
|
|
|
||
|
|
if (!firstcall)
|
||
|
|
{
|
||
|
|
lastlistn =
|
||
|
|
nl->Append(lastlistn,
|
||
|
|
nl->TwoElemList(nl->SymbolAtom(attrname),
|
||
|
|
nl->Second(first2)));
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
firstcall = false;
|
||
|
|
listn = nl->OneElemList(nl->TwoElemList(nl->SymbolAtom(attrname),
|
||
|
|
nl->Second(first2)));
|
||
|
|
lastlistn = listn;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return
|
||
|
|
nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()),
|
||
|
|
nl->TwoElemList(nl->SymbolAtom(CcTuple::BasicType()),
|
||
|
|
listn));
|
||
|
|
}
|
||
|
|
ErrorReporter::ReportError("Incorrect input for operator rename.");
|
||
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
||
|
|
}
|
||
|
|
ErrorReporter::ReportError("Incorrect input for operator rename.");
|
||
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
||
|
|
}
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.2 Value mapping function of operator ~rename~
|
||
|
|
|
||
|
|
*/
|
||
|
|
static int
|
||
|
|
CcRename(Word* args, Word& result, int message, Word& local, Supplier s)
|
||
|
|
{
|
||
|
|
Word t;
|
||
|
|
CcTuple* tuple;
|
||
|
|
|
||
|
|
switch (message)
|
||
|
|
{
|
||
|
|
case OPEN :
|
||
|
|
|
||
|
|
qp->Open(args[0].addr);
|
||
|
|
return 0;
|
||
|
|
|
||
|
|
case REQUEST :
|
||
|
|
|
||
|
|
qp->Request(args[0].addr,t);
|
||
|
|
if (qp->Received(args[0].addr))
|
||
|
|
{
|
||
|
|
tuple = (CcTuple*)t.addr;
|
||
|
|
result = SetWord(tuple);
|
||
|
|
return YIELD;
|
||
|
|
}
|
||
|
|
else return CANCEL;
|
||
|
|
|
||
|
|
case CLOSE :
|
||
|
|
|
||
|
|
qp->Close(args[0].addr);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Specification of operator ~rename~
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string CcRenameSpec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
||
|
|
"\"Example\" ) "
|
||
|
|
"( <text>((stream (mtuple([a1:d1, ... ,"
|
||
|
|
"an:dn)))ar) -> (stream (mtuple([a1ar:d1, "
|
||
|
|
"... ,anar:dn)))</text--->"
|
||
|
|
"<text>_ rename [ _ ] or just _ { _ }"
|
||
|
|
"</text--->"
|
||
|
|
"<text>Renames all attribute names by adding"
|
||
|
|
" them with the postfix passed as parameter. "
|
||
|
|
"NOTE: parameter must be of symbol type."
|
||
|
|
"</text--->"
|
||
|
|
"<text>query ten feed rename [ r1 ] consume "
|
||
|
|
"or query ten feed {r1} consume, the result "
|
||
|
|
"has format e.g. n_r1</text--->"
|
||
|
|
") )";
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Definition of operator ~rename~
|
||
|
|
|
||
|
|
*/
|
||
|
|
Operator ccrelrename (
|
||
|
|
"rename", // name
|
||
|
|
CcRenameSpec, // specification
|
||
|
|
CcRename, // value mapping
|
||
|
|
Operator::SimpleSelect, // trivial selection function
|
||
|
|
CcRenameTypeMap // type mapping
|
||
|
|
);
|
||
|
|
/*
|
||
|
|
|
||
|
|
7.3 Operator ~extract~
|
||
|
|
|
||
|
|
This operator has a stream of tuples and the name of an attribut as input and
|
||
|
|
returns the value of this attribute
|
||
|
|
from the first tuple of the input stream. If the input stream is empty a run
|
||
|
|
time error occurs. In this case value -1 will be returned.
|
||
|
|
|
||
|
|
7.3.1 Type mapping function of operator ~extract~
|
||
|
|
|
||
|
|
Type mapping for ~extract~ is
|
||
|
|
|
||
|
|
---- ((stream (mtuple ((x1 t1)...(xn tn))) xi) -> ti
|
||
|
|
APPEND (i) ti)
|
||
|
|
----
|
||
|
|
|
||
|
|
*/
|
||
|
|
static ListExpr
|
||
|
|
CcExtractTypeMap( ListExpr args )
|
||
|
|
{
|
||
|
|
ListExpr first, second, attrtype;
|
||
|
|
string attrname;
|
||
|
|
int j;
|
||
|
|
|
||
|
|
if(nl->ListLength(args) == 2)
|
||
|
|
{
|
||
|
|
first = nl->First(args);
|
||
|
|
second = nl->Second(args);
|
||
|
|
|
||
|
|
if((nl->ListLength(first) == 2 ) &&
|
||
|
|
(CcTypeOfRelAlgSymbol(nl->First(first)) == mstream) &&
|
||
|
|
(CcTypeOfRelAlgSymbol(nl->First(nl->Second(first))) == mtuple) &&
|
||
|
|
(nl->IsAtom(second)) &&
|
||
|
|
(nl->AtomType(second) == SymbolType))
|
||
|
|
{
|
||
|
|
attrname = nl->SymbolValue(second);
|
||
|
|
j = CcFindAttribute(nl->Second(nl->Second(first)), attrname,
|
||
|
|
attrtype, nl);
|
||
|
|
if (j)
|
||
|
|
return nl->ThreeElemList(nl->SymbolAtom(Symbol::APPEND()),
|
||
|
|
nl->OneElemList(nl->IntAtom(j)), attrtype);
|
||
|
|
}
|
||
|
|
ErrorReporter::ReportError("Incorrect input for operator extract.");
|
||
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
||
|
|
}
|
||
|
|
ErrorReporter::ReportError("Incorrect input for operator extract.");
|
||
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
||
|
|
}
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.2 Value mapping function of operator ~extract~
|
||
|
|
|
||
|
|
The argument vector ~args~ contains in the first slot ~args[0]~ the tuple
|
||
|
|
and in ~args[2]~ the position of the attribute as a number. Returns as
|
||
|
|
~result~ the value of an attribute at the given position ~args[2]~ in a
|
||
|
|
tuple object.
|
||
|
|
|
||
|
|
*/
|
||
|
|
static int
|
||
|
|
CcExtract(Word* args, Word& result, int message, Word& local, Supplier s)
|
||
|
|
{
|
||
|
|
Word t;
|
||
|
|
CcTuple* tupleptr;
|
||
|
|
int index;
|
||
|
|
Attribute* res = (Attribute*)((qp->ResultStorage(s)).addr);
|
||
|
|
result = SetWord(res);
|
||
|
|
|
||
|
|
qp->Open(args[0].addr);
|
||
|
|
qp->Request(args[0].addr,t);
|
||
|
|
|
||
|
|
if (qp->Received(args[0].addr))
|
||
|
|
{
|
||
|
|
tupleptr = (CcTuple*)t.addr;
|
||
|
|
index = ((CcInt*)args[2].addr)->GetIntval();
|
||
|
|
assert((1 <= index) && (index <= tupleptr->GetNoAttrs()));
|
||
|
|
res->CopyFrom((const Attribute*)tupleptr->Get(index - 1));
|
||
|
|
tupleptr->DeleteIfAllowed();
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
res->SetDefined(false);
|
||
|
|
}
|
||
|
|
|
||
|
|
qp->Close(args[0].addr);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Specification of operator ~extract~
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string CcExtractSpec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
||
|
|
"\"Example\" ) "
|
||
|
|
"( <text>((stream (mtuple([a1:d1, ... ,an:dn]"
|
||
|
|
"))) x ai) -> di</text--->"
|
||
|
|
"<text>_ extract [ _ ]</text--->"
|
||
|
|
"<text>Returns the value of attribute ai of "
|
||
|
|
"the first tuple in the input stream."
|
||
|
|
"</text--->"
|
||
|
|
"<text>query cities feed extract [population]"
|
||
|
|
"</text--->"
|
||
|
|
") )";
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Definition of operator ~extract~
|
||
|
|
|
||
|
|
*/
|
||
|
|
Operator ccrelextract (
|
||
|
|
"extract", // name
|
||
|
|
CcExtractSpec, // specification
|
||
|
|
CcExtract, // value mapping
|
||
|
|
Operator::SimpleSelect, // trivial selection function
|
||
|
|
CcExtractTypeMap // type mapping
|
||
|
|
);
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
7.3 Operator ~head~
|
||
|
|
|
||
|
|
This operator fetches the first n tuples from a stream.
|
||
|
|
|
||
|
|
7.3.1 Type mapping function of operator ~head~
|
||
|
|
|
||
|
|
Type mapping for ~head~ is
|
||
|
|
|
||
|
|
---- ((stream (mtuple ((x1 t1)...(xn tn))) int) ->
|
||
|
|
((stream (mtuple ((x1 t1)...(xn tn))))
|
||
|
|
----
|
||
|
|
|
||
|
|
*/
|
||
|
|
static ListExpr
|
||
|
|
CcHeadTypeMap( ListExpr args )
|
||
|
|
{
|
||
|
|
ListExpr first, second;
|
||
|
|
|
||
|
|
if(nl->ListLength(args) == 2)
|
||
|
|
{
|
||
|
|
first = nl->First(args);
|
||
|
|
second = nl->Second(args);
|
||
|
|
|
||
|
|
if((nl->ListLength(first) == 2 )
|
||
|
|
&& (CcTypeOfRelAlgSymbol(nl->First(first)) == mstream)
|
||
|
|
&& (CcTypeOfRelAlgSymbol(nl->First(nl->Second(first))) == mtuple)
|
||
|
|
&& CcIsTupleDescription(nl->Second(nl->Second(first)), nl)
|
||
|
|
&& (nl->IsAtom(second))
|
||
|
|
&& (nl->AtomType(second) == SymbolType)
|
||
|
|
&& nl->SymbolValue(second) == CcInt::BasicType())
|
||
|
|
{
|
||
|
|
return first;
|
||
|
|
}
|
||
|
|
ErrorReporter::ReportError("Incorrect input for operator head.");
|
||
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
||
|
|
}
|
||
|
|
ErrorReporter::ReportError("Incorrect input for operator head.");
|
||
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
||
|
|
}
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.2 Value mapping function of operator ~head~
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
static int
|
||
|
|
CcHead(Word* args, Word& result, int message, Word& local, Supplier s)
|
||
|
|
{
|
||
|
|
Word tupleWord;
|
||
|
|
CcTuple* tuple;
|
||
|
|
|
||
|
|
switch(message)
|
||
|
|
{
|
||
|
|
case OPEN:
|
||
|
|
|
||
|
|
//cout << "head OPEN" << endl;
|
||
|
|
|
||
|
|
qp->Open(args[0].addr);
|
||
|
|
local.addr = new int(((CcInt*)args[1].addr)->GetIntval());
|
||
|
|
return 0;
|
||
|
|
|
||
|
|
case REQUEST:{
|
||
|
|
|
||
|
|
//cout << "head REQUEST" << endl;
|
||
|
|
int* c = static_cast<int*>(local.addr);
|
||
|
|
if( (*c) <= 0)
|
||
|
|
{
|
||
|
|
return CANCEL;
|
||
|
|
}
|
||
|
|
|
||
|
|
qp->Request(args[0].addr, tupleWord);
|
||
|
|
if(qp->Received(args[0].addr))
|
||
|
|
{
|
||
|
|
tuple = (CcTuple*)tupleWord.addr;
|
||
|
|
result = SetWord(tuple);
|
||
|
|
(*(c))--;
|
||
|
|
return YIELD;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
return CANCEL;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
case CLOSE:
|
||
|
|
|
||
|
|
//cout << "head CLOSE" << endl;
|
||
|
|
|
||
|
|
qp->Close(args[0].addr);
|
||
|
|
if(local.addr){
|
||
|
|
int* li = static_cast<int*>(local.addr);
|
||
|
|
delete li;
|
||
|
|
local.addr=0;
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Specification of operator ~head~
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string CcHeadSpec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
||
|
|
"\"Example\" ) "
|
||
|
|
"( <text>((stream (mtuple([a1:d1, ... ,an:dn]"
|
||
|
|
"))) x int) -> (stream (mtuple([a1:d1, ... ,"
|
||
|
|
"an:dn])))</text--->"
|
||
|
|
"<text>_ head [ _ ]</text--->"
|
||
|
|
"<text>Returns the first n tuples in the input "
|
||
|
|
"stream.</text--->"
|
||
|
|
"<text>query cities feed head[10] consume"
|
||
|
|
"</text--->"
|
||
|
|
") )";
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Definition of operator ~head~
|
||
|
|
|
||
|
|
*/
|
||
|
|
Operator ccrelhead (
|
||
|
|
"head", // name
|
||
|
|
CcHeadSpec, // specification
|
||
|
|
CcHead, // value mapping
|
||
|
|
Operator::SimpleSelect, // trivial selection function
|
||
|
|
CcHeadTypeMap // type mapping
|
||
|
|
);
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
7.3 Operators ~max~ and ~min~
|
||
|
|
|
||
|
|
|
||
|
|
7.3.1 Type mapping function of Operators ~max~ and ~min~
|
||
|
|
|
||
|
|
Type mapping for ~max~ and ~min~ is
|
||
|
|
|
||
|
|
---- ((stream (mtuple ((x1 t1)...(xn tn))) xi) -> ti
|
||
|
|
APPEND (i ti)
|
||
|
|
----
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<bool isMax> ListExpr
|
||
|
|
CcMaxMinTypeMap( ListExpr args )
|
||
|
|
{
|
||
|
|
ListExpr first, second, attrtype;
|
||
|
|
string attrname;
|
||
|
|
int j;
|
||
|
|
const char* errorMessage =
|
||
|
|
isMax ?
|
||
|
|
"Incorrect input for operator max."
|
||
|
|
: "Incorrect input for operator min.";
|
||
|
|
|
||
|
|
if(nl->ListLength(args) == 2)
|
||
|
|
{
|
||
|
|
first = nl->First(args);
|
||
|
|
second = nl->Second(args);
|
||
|
|
|
||
|
|
if((nl->ListLength(first) == 2 )
|
||
|
|
&& (CcTypeOfRelAlgSymbol(nl->First(first)) == mstream)
|
||
|
|
&& (CcTypeOfRelAlgSymbol(nl->First(nl->Second(first))) == mtuple)
|
||
|
|
&& CcIsTupleDescription(nl->Second(nl->Second(first)), nl)
|
||
|
|
&& (nl->IsAtom(second))
|
||
|
|
&& (nl->AtomType(second) == SymbolType))
|
||
|
|
{
|
||
|
|
attrname = nl->SymbolValue(second);
|
||
|
|
j = CcFindAttribute(nl->Second(nl->Second(first)), attrname,
|
||
|
|
attrtype, nl);
|
||
|
|
|
||
|
|
if (j > 0
|
||
|
|
&& (nl->SymbolValue(attrtype) == CcReal::BasicType()
|
||
|
|
|| nl->SymbolValue(attrtype) == CcString::BasicType()
|
||
|
|
|| nl->SymbolValue(attrtype) == CcBool::BasicType()
|
||
|
|
|| nl->SymbolValue(attrtype) == CcInt::BasicType()))
|
||
|
|
{
|
||
|
|
return nl->ThreeElemList(nl->SymbolAtom(Symbol::APPEND()),
|
||
|
|
nl->OneElemList(nl->IntAtom(j)), attrtype);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
ErrorReporter::ReportError(errorMessage);
|
||
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
||
|
|
}
|
||
|
|
ErrorReporter::ReportError(errorMessage);
|
||
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
||
|
|
}
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.2 Value mapping function of operators ~max~ and ~min~
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
template<bool isMax> int
|
||
|
|
CcMaxMinValueMapping(Word* args, Word& result, int message,
|
||
|
|
Word& local, Supplier s)
|
||
|
|
{
|
||
|
|
bool definedValueFound = false;
|
||
|
|
Word currentTupleWord;
|
||
|
|
Attribute* extremum = (Attribute*)(qp->ResultStorage(s)).addr;
|
||
|
|
extremum->SetDefined(false);
|
||
|
|
result = SetWord(extremum);
|
||
|
|
|
||
|
|
assert(args[2].addr != 0);
|
||
|
|
int attributeIndex = ((CcInt*)args[2].addr)->GetIntval() - 1;
|
||
|
|
|
||
|
|
qp->Open(args[0].addr);
|
||
|
|
qp->Request(args[0].addr, currentTupleWord);
|
||
|
|
while(qp->Received(args[0].addr))
|
||
|
|
{
|
||
|
|
CcTuple* currentTuple = (CcTuple*)currentTupleWord.addr;
|
||
|
|
const Attribute* currentAttr =
|
||
|
|
(const Attribute*)currentTuple->Get(attributeIndex);
|
||
|
|
if(currentAttr->IsDefined())
|
||
|
|
{
|
||
|
|
if(definedValueFound)
|
||
|
|
{
|
||
|
|
if(isMax)
|
||
|
|
{
|
||
|
|
if(currentAttr->Compare(extremum) > 0)
|
||
|
|
{
|
||
|
|
extremum->CopyFrom(currentAttr);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
if(currentAttr->Compare(extremum) < 0)
|
||
|
|
{
|
||
|
|
extremum->CopyFrom(currentAttr);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
definedValueFound = true;
|
||
|
|
extremum->CopyFrom(currentAttr);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
currentTuple->DeleteIfAllowed();
|
||
|
|
qp->Request(args[0].addr, currentTupleWord);
|
||
|
|
}
|
||
|
|
qp->Close(args[0].addr);
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Specification of operator ~max~
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string CcMaxOpSpec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
||
|
|
"\"Example\" ) "
|
||
|
|
"( <text>((stream (mtuple([a1:d1, ... ,an:dn]"
|
||
|
|
"))) x ai) -> di</text--->"
|
||
|
|
"<text>_ _ mergesec</text--->"
|
||
|
|
"<text>Returns the maximum value of attribute "
|
||
|
|
"ai over the input stream.</text--->"
|
||
|
|
"<text>query cities feed max [ cityname ]"
|
||
|
|
"</text--->"
|
||
|
|
") )";
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Definition of operator ~max~
|
||
|
|
|
||
|
|
*/
|
||
|
|
Operator ccrelmax (
|
||
|
|
"max", // name
|
||
|
|
CcMaxOpSpec, // specification
|
||
|
|
CcMaxMinValueMapping<true>, // value mapping
|
||
|
|
Operator::SimpleSelect, // trivial selection function
|
||
|
|
CcMaxMinTypeMap<true> // type mapping
|
||
|
|
);
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Specification of operator ~min~
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string CcMinOpSpec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
||
|
|
"\"Example\" ) "
|
||
|
|
"( <text>((stream (mtuple([a1:d1, ... ,an:dn])))"
|
||
|
|
" x ai) -> di</text--->"
|
||
|
|
"<text>_ min [ _ ]</text--->"
|
||
|
|
"<text>Returns the minimum value of attribute ai "
|
||
|
|
"over the input stream.</text--->"
|
||
|
|
"<text>query cities feed min [ cityname ]"
|
||
|
|
"</text--->"
|
||
|
|
") )";
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Definition of operator ~min~
|
||
|
|
|
||
|
|
*/
|
||
|
|
Operator ccrelmin (
|
||
|
|
"min", // name
|
||
|
|
CcMinOpSpec, // specification
|
||
|
|
CcMaxMinValueMapping<false>, // value mapping
|
||
|
|
Operator::SimpleSelect, // trivial selection function
|
||
|
|
CcMaxMinTypeMap<false> // type mapping
|
||
|
|
);
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
7.3 Operators ~avg~ and ~sum~
|
||
|
|
|
||
|
|
|
||
|
|
7.3.1 Type mapping function of Operators ~avg~ and ~sum~
|
||
|
|
|
||
|
|
Type mapping for ~avg~ is
|
||
|
|
|
||
|
|
---- ((stream (mtuple ((x1 t1)...(xn tn))) xi) -> real
|
||
|
|
APPEND (i ti)
|
||
|
|
----
|
||
|
|
|
||
|
|
Type mapping for ~sum~ is
|
||
|
|
|
||
|
|
---- ((stream (mtuple ((x1 t1)...(xn tn))) xi) -> ti
|
||
|
|
APPEND (i ti)
|
||
|
|
----
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
template<bool isAvg> ListExpr
|
||
|
|
CcAvgSumTypeMap( ListExpr args )
|
||
|
|
{
|
||
|
|
ListExpr first, second, attrtype;
|
||
|
|
string attrname;
|
||
|
|
int j;
|
||
|
|
const char* errorMessage =
|
||
|
|
isAvg ?
|
||
|
|
"Incorrect input for operator avg."
|
||
|
|
: "Incorrect input for operator sum.";
|
||
|
|
|
||
|
|
|
||
|
|
if(nl->ListLength(args) == 2)
|
||
|
|
{
|
||
|
|
first = nl->First(args);
|
||
|
|
second = nl->Second(args);
|
||
|
|
|
||
|
|
if((nl->ListLength(first) == 2 )
|
||
|
|
&& (CcTypeOfRelAlgSymbol(nl->First(first)) == mstream)
|
||
|
|
&& (CcTypeOfRelAlgSymbol(nl->First(nl->Second(first))) == mtuple)
|
||
|
|
&& CcIsTupleDescription(nl->Second(nl->Second(first)), nl)
|
||
|
|
&& (nl->IsAtom(second))
|
||
|
|
&& (nl->AtomType(second) == SymbolType))
|
||
|
|
{
|
||
|
|
attrname = nl->SymbolValue(second);
|
||
|
|
j = CcFindAttribute(nl->Second(nl->Second(first)), attrname,
|
||
|
|
attrtype, nl);
|
||
|
|
|
||
|
|
if (j > 0
|
||
|
|
&& (nl->SymbolValue(attrtype) == CcReal::BasicType()
|
||
|
|
|| nl->SymbolValue(attrtype) == CcInt::BasicType()))
|
||
|
|
{
|
||
|
|
return nl->ThreeElemList(nl->SymbolAtom(Symbol::APPEND()),
|
||
|
|
nl->TwoElemList(nl->IntAtom(j),
|
||
|
|
nl->StringAtom(nl->SymbolValue(attrtype))),
|
||
|
|
isAvg ? nl->SymbolAtom(CcReal::BasicType()) : attrtype);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
ErrorReporter::ReportError(errorMessage);
|
||
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
||
|
|
}
|
||
|
|
ErrorReporter::ReportError(errorMessage);
|
||
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.2 Value mapping function of operators ~avg~ and ~sum~
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<bool isAvg> int
|
||
|
|
CcAvgSumValueMapping(Word* args, Word& result, int message,
|
||
|
|
Word& local, Supplier s)
|
||
|
|
{
|
||
|
|
bool definedValueFound = false;
|
||
|
|
Word currentTupleWord;
|
||
|
|
Attribute* accumulated = 0;
|
||
|
|
int nProcessedItems = 0;
|
||
|
|
|
||
|
|
assert(args[2].addr != 0);
|
||
|
|
assert(args[3].addr != 0);
|
||
|
|
|
||
|
|
int attributeIndex = ((CcInt*)args[2].addr)->GetIntval() - 1;
|
||
|
|
const STRING_T *attributeType = ((CcString*)args[3].addr)->GetStringval();
|
||
|
|
|
||
|
|
qp->Open(args[0].addr);
|
||
|
|
qp->Request(args[0].addr, currentTupleWord);
|
||
|
|
while(qp->Received(args[0].addr))
|
||
|
|
{
|
||
|
|
CcTuple* currentTuple = (CcTuple*)currentTupleWord.addr;
|
||
|
|
Attribute* currentAttr = (Attribute*)currentTuple->Get(attributeIndex);
|
||
|
|
if(currentAttr->IsDefined())
|
||
|
|
{
|
||
|
|
nProcessedItems++;
|
||
|
|
|
||
|
|
if(definedValueFound)
|
||
|
|
{
|
||
|
|
if(strcmp(*attributeType, CcReal::BasicType().c_str()) == 0)
|
||
|
|
{
|
||
|
|
CcReal* accumulatedReal = (CcReal*)accumulated;
|
||
|
|
CcReal* currentReal = (CcReal*)currentAttr;
|
||
|
|
accumulatedReal->Set(currentReal->GetRealval()
|
||
|
|
+ accumulatedReal->GetRealval());
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
CcInt* accumulatedInt = (CcInt*)accumulated;
|
||
|
|
CcInt* currentInt = (CcInt*)currentAttr;
|
||
|
|
accumulatedInt->Set(currentInt->GetIntval()
|
||
|
|
+ accumulatedInt->GetIntval());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
definedValueFound = true;
|
||
|
|
accumulated = currentAttr->Clone();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
currentTuple->DeleteIfAllowed();
|
||
|
|
qp->Request(args[0].addr, currentTupleWord);
|
||
|
|
}
|
||
|
|
qp->Close(args[0].addr);
|
||
|
|
|
||
|
|
if(definedValueFound)
|
||
|
|
{
|
||
|
|
if(isAvg)
|
||
|
|
{
|
||
|
|
CcReal* resultAttr = (CcReal*)(qp->ResultStorage(s).addr);
|
||
|
|
SEC_STD_REAL nItems = (SEC_STD_REAL)nProcessedItems;
|
||
|
|
|
||
|
|
if(strcmp(*attributeType, CcReal::BasicType().c_str()) == 0)
|
||
|
|
{
|
||
|
|
CcReal* accumulatedReal = (CcReal*)accumulated;
|
||
|
|
resultAttr->Set(accumulatedReal->GetRealval() / nItems);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
CcInt* accumulatedInt = (CcInt*)accumulated;
|
||
|
|
resultAttr->Set(((SEC_STD_REAL)accumulatedInt->GetIntval()) / nItems);
|
||
|
|
}
|
||
|
|
delete accumulated;
|
||
|
|
result = SetWord(resultAttr);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
if(strcmp(*attributeType, CcReal::BasicType().c_str()) == 0)
|
||
|
|
{
|
||
|
|
CcReal* resultAttr = (CcReal*)(qp->ResultStorage(s).addr);
|
||
|
|
CcReal* accumulatedReal = (CcReal*)accumulated;
|
||
|
|
resultAttr->Set(accumulatedReal->GetRealval());
|
||
|
|
result = SetWord(resultAttr);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
CcInt* resultAttr = (CcInt*)(qp->ResultStorage(s).addr);
|
||
|
|
CcInt* accumulatedInt = (CcInt*)accumulated;
|
||
|
|
resultAttr->Set(accumulatedInt->GetIntval());
|
||
|
|
result = SetWord(resultAttr);
|
||
|
|
}
|
||
|
|
delete accumulated;
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
((Attribute*)qp->ResultStorage(s).addr)->SetDefined(false);
|
||
|
|
result = qp->ResultStorage(s);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Specification of operator ~avg~
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string CcAvgOpSpec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
||
|
|
"\"Example\" ) "
|
||
|
|
"( <text>((stream (mtuple([a1:d1, ... ,an:dn]"
|
||
|
|
"))) x ai) -> real</text--->"
|
||
|
|
"<text>_ avg [ _ ]</text--->"
|
||
|
|
"<text>Returns the average value of attribute "
|
||
|
|
"ai over the input stream.</text--->"
|
||
|
|
"<text>query cities feed avg [population]"
|
||
|
|
"</text--->"
|
||
|
|
") )";
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Definition of operator ~avg~
|
||
|
|
|
||
|
|
*/
|
||
|
|
Operator ccrelavg (
|
||
|
|
"avg", // name
|
||
|
|
CcAvgOpSpec, // specification
|
||
|
|
CcAvgSumValueMapping<true>, // value mapping
|
||
|
|
Operator::SimpleSelect, // trivial selection function
|
||
|
|
CcAvgSumTypeMap<true> // type mapping
|
||
|
|
);
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Specification of operator ~sum~
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string CcSumOpSpec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
||
|
|
"\"Example\" ) "
|
||
|
|
"( <text>((stream (mtuple([a1:d1, ... ,an:dn]"
|
||
|
|
"))) x ai) -> di</text--->"
|
||
|
|
"<text>_ sum [ _ ]</text--->"
|
||
|
|
"<text>Returns the sum of the values of attribute"
|
||
|
|
" ai over the input stream.</text--->"
|
||
|
|
"<text>query cities feed sum[population]"
|
||
|
|
"</text--->"
|
||
|
|
") )";
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Definition of operator ~sum~
|
||
|
|
|
||
|
|
*/
|
||
|
|
Operator ccrelsum (
|
||
|
|
"sum", // name
|
||
|
|
CcSumOpSpec, // specification
|
||
|
|
CcAvgSumValueMapping<false>, // value mapping
|
||
|
|
Operator::SimpleSelect, // trivial selection function
|
||
|
|
CcAvgSumTypeMap<false> // type mapping
|
||
|
|
);
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
7.3 Operator ~sortBy~
|
||
|
|
|
||
|
|
This operator sorts a stream of tuples by a given list of attributes.
|
||
|
|
For each attribute it must be specified wether the list should be sorted
|
||
|
|
in ascending (asc) or descending (desc) order with regard to that attribute.
|
||
|
|
|
||
|
|
7.3.1 Type mapping function of operator ~sortBy~
|
||
|
|
|
||
|
|
Type mapping for ~sortBy~ is
|
||
|
|
|
||
|
|
---- ((stream (mtuple ((x1 t1)...(xn tn))) ((xi1 asc/desc) ... (xij asc/desc)))
|
||
|
|
-> (stream (mtuple ((x1 t1)...(xn tn)))
|
||
|
|
APPEND (j i1 asc/desc i2 asc/desc ... ij asc/desc)
|
||
|
|
----
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
const char* sortAscending = "asc";
|
||
|
|
const char* sortDescending = "desc";
|
||
|
|
|
||
|
|
static ListExpr
|
||
|
|
CcSortByTypeMap( ListExpr args )
|
||
|
|
{
|
||
|
|
ListExpr attrtype;
|
||
|
|
string attrname;
|
||
|
|
|
||
|
|
if(nl->ListLength(args) == 2)
|
||
|
|
{
|
||
|
|
ListExpr streamDesc = nl->First(args);
|
||
|
|
ListExpr sortSpec = nl->Second(args);
|
||
|
|
|
||
|
|
if((nl->ListLength(streamDesc) == 2 ) &&
|
||
|
|
(CcTypeOfRelAlgSymbol(nl->First(streamDesc)) == mstream) &&
|
||
|
|
(CcTypeOfRelAlgSymbol(nl->First(nl->Second(streamDesc))) == mtuple))
|
||
|
|
{
|
||
|
|
int numberOfSortAttrs = nl->ListLength(sortSpec);
|
||
|
|
if(numberOfSortAttrs > 0)
|
||
|
|
{
|
||
|
|
ListExpr sortOrderDesc =
|
||
|
|
nl->OneElemList(nl->IntAtom(numberOfSortAttrs));
|
||
|
|
ListExpr sortOrderDescLast = sortOrderDesc;
|
||
|
|
ListExpr rest = sortSpec;
|
||
|
|
while(!nl->IsEmpty(rest))
|
||
|
|
{
|
||
|
|
ListExpr attrSpec = nl->First(rest);
|
||
|
|
rest = nl->Rest(rest);
|
||
|
|
if((nl->ListLength(attrSpec) == 2)
|
||
|
|
&& (nl->IsAtom(nl->First(attrSpec)))
|
||
|
|
&& (nl->AtomType(nl->First(attrSpec)) == SymbolType)
|
||
|
|
&& (nl->IsAtom(nl->Second(attrSpec)))
|
||
|
|
&& (nl->AtomType(nl->Second(attrSpec)) == SymbolType))
|
||
|
|
{
|
||
|
|
attrname = nl->SymbolValue(nl->First(attrSpec));
|
||
|
|
int j = CcFindAttribute(nl->Second(nl->Second(streamDesc)),
|
||
|
|
attrname, attrtype, nl);
|
||
|
|
if ((j > 0)
|
||
|
|
&& ((nl->SymbolValue(nl->Second(attrSpec)) == sortAscending)
|
||
|
|
|| (nl->SymbolValue(nl->Second(attrSpec)) == sortDescending)))
|
||
|
|
{
|
||
|
|
sortOrderDescLast =
|
||
|
|
nl->Append(sortOrderDescLast, nl->IntAtom(j));
|
||
|
|
bool isAscending =
|
||
|
|
nl->SymbolValue(nl->Second(attrSpec)) == sortAscending;
|
||
|
|
sortOrderDescLast =
|
||
|
|
nl->Append(sortOrderDescLast,
|
||
|
|
nl->BoolAtom(isAscending));
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
ErrorReporter::ReportError(
|
||
|
|
"Incorrect input for operator sortby.");
|
||
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
ErrorReporter::ReportError("Incorrect input for operator sortby.");
|
||
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return nl->ThreeElemList(nl->SymbolAtom(Symbol::APPEND()),
|
||
|
|
sortOrderDesc, streamDesc);
|
||
|
|
};
|
||
|
|
ErrorReporter::ReportError("Incorrect input for operator sortby.");
|
||
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
||
|
|
}
|
||
|
|
ErrorReporter::ReportError("Incorrect input for operator sortby.");
|
||
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
||
|
|
}
|
||
|
|
ErrorReporter::ReportError("Incorrect input for operator sortby.");
|
||
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.2 Value mapping function of operator ~sortBy~
|
||
|
|
|
||
|
|
The argument vector ~args~ contains in the first slot ~args[0]~ the stream and
|
||
|
|
in ~args[2]~ the number of sort attributes. ~args[3]~ contains the index of the first
|
||
|
|
sort attribute, ~args[4]~ a boolean indicating wether the stream is sorted in
|
||
|
|
ascending order with regard to the sort first attribute. ~args[5]~ and ~args[6]~
|
||
|
|
contain these values for the second sort attribute and so on.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
typedef vector< pair<int, bool> > CcSortOrderSpecification;
|
||
|
|
|
||
|
|
class CcTupleCmp
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
CcSortOrderSpecification spec;
|
||
|
|
bool operator()(const CcTuple* aConst, const CcTuple* bConst) const
|
||
|
|
{
|
||
|
|
CcTuple* a = (CcTuple*)aConst;
|
||
|
|
CcTuple* b = (CcTuple*)bConst;
|
||
|
|
|
||
|
|
CcSortOrderSpecification::const_iterator iter = spec.begin();
|
||
|
|
while(iter != spec.end())
|
||
|
|
{
|
||
|
|
if(((Attribute*)a->Get(iter->first - 1))->
|
||
|
|
Compare(((Attribute*)b->Get(iter->first - 1))) < 0)
|
||
|
|
{
|
||
|
|
return iter->second;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
if(((Attribute*)a->Get(iter->first - 1))->
|
||
|
|
Compare(((Attribute*)b->Get(iter->first - 1))) > 0)
|
||
|
|
{
|
||
|
|
return !(iter->second);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
iter++;
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
struct CcSortByLocalInfo
|
||
|
|
{
|
||
|
|
vector<CcTuple*>* tuples;
|
||
|
|
size_t currentIndex;
|
||
|
|
};
|
||
|
|
|
||
|
|
CPUTimeMeasurer ccSortMeasurer;
|
||
|
|
|
||
|
|
template<bool lexicographically> int
|
||
|
|
CcSortBy(Word* args, Word& result, int message, Word& local, Supplier s)
|
||
|
|
{
|
||
|
|
Word tuple;
|
||
|
|
vector<CcTuple*>* tuples;
|
||
|
|
CcSortByLocalInfo* localInfo;
|
||
|
|
CcSortOrderSpecification spec;
|
||
|
|
int i;
|
||
|
|
size_t j;
|
||
|
|
int sortAttrIndex;
|
||
|
|
int nSortAttrs;
|
||
|
|
bool sortOrderIsAscending;
|
||
|
|
CcTupleCmp ccCmp;
|
||
|
|
LexicographicalCcTupleCmp lCcCmp;
|
||
|
|
CcTuple* t;
|
||
|
|
|
||
|
|
switch(message)
|
||
|
|
{
|
||
|
|
case OPEN:
|
||
|
|
tuples = new vector<CcTuple*>;
|
||
|
|
qp->Open(args[0].addr);
|
||
|
|
qp->Request(args[0].addr,tuple);
|
||
|
|
while(qp->Received(args[0].addr))
|
||
|
|
{
|
||
|
|
t =(CcTuple*)tuple.addr;
|
||
|
|
tuples->push_back(t);
|
||
|
|
qp->Request(args[0].addr,tuple);
|
||
|
|
}
|
||
|
|
qp->Close(args[0].addr);
|
||
|
|
|
||
|
|
if(lexicographically)
|
||
|
|
{
|
||
|
|
ccSortMeasurer.Enter();
|
||
|
|
sort(tuples->begin(), tuples->end(), lCcCmp);
|
||
|
|
ccSortMeasurer.Exit();
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
nSortAttrs = ((CcInt*)args[2].addr)->GetIntval();
|
||
|
|
for(i = 1; i <= nSortAttrs; i++)
|
||
|
|
{
|
||
|
|
sortAttrIndex = ((CcInt*)args[2 * i + 1].addr)->GetIntval();
|
||
|
|
sortOrderIsAscending = ((CcBool*)args[2 * i + 2].addr)->GetBoolval();
|
||
|
|
spec.push_back(pair<int, bool>(sortAttrIndex, sortOrderIsAscending));
|
||
|
|
};
|
||
|
|
ccCmp.spec = spec;
|
||
|
|
|
||
|
|
ccSortMeasurer.Enter();
|
||
|
|
sort(tuples->begin(), tuples->end(), ccCmp);
|
||
|
|
ccSortMeasurer.Exit();
|
||
|
|
}
|
||
|
|
|
||
|
|
ccSortMeasurer.PrintCPUTimeAndReset("CPU Time for Sorting Tuples : ");
|
||
|
|
|
||
|
|
localInfo = new CcSortByLocalInfo;
|
||
|
|
localInfo->tuples = tuples;
|
||
|
|
localInfo->currentIndex = 0;
|
||
|
|
local = SetWord(localInfo);
|
||
|
|
return 0;
|
||
|
|
case REQUEST:
|
||
|
|
localInfo = (CcSortByLocalInfo*)local.addr;
|
||
|
|
tuples = localInfo->tuples;
|
||
|
|
if(localInfo->currentIndex + 1 <= tuples->size())
|
||
|
|
{
|
||
|
|
result = SetWord((*tuples)[localInfo->currentIndex]);
|
||
|
|
localInfo->currentIndex++;
|
||
|
|
return YIELD;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
return CANCEL;
|
||
|
|
}
|
||
|
|
case CLOSE:
|
||
|
|
localInfo = (CcSortByLocalInfo*)local.addr;
|
||
|
|
if(localInfo)
|
||
|
|
{
|
||
|
|
for(j = localInfo->currentIndex;
|
||
|
|
j + 1 <= localInfo->tuples->size(); j++)
|
||
|
|
{
|
||
|
|
(*(localInfo->tuples))[j]->DeleteIfAllowed();
|
||
|
|
}
|
||
|
|
|
||
|
|
delete localInfo->tuples;
|
||
|
|
delete localInfo;
|
||
|
|
local = SetWord(Address(0));
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Specification of operator ~sortBy~
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string CcSortBySpec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
||
|
|
"\"Example\" ) "
|
||
|
|
"( <text>((stream (mtuple([a1:d1, ... ,an:dn])))"
|
||
|
|
" ((xi1 asc/desc) ... (xij asc/desc))) -> "
|
||
|
|
"(stream (mtuple([a1:d1, ... ,an:dn])))</text--->"
|
||
|
|
"<text>_ sortby [list]</text--->"
|
||
|
|
"<text>Sorts input stream according to a list "
|
||
|
|
"of attributes ai1 ... aij.</text--->"
|
||
|
|
"<text>query employee feed sortby[DeptNo asc] "
|
||
|
|
"consume</text--->"
|
||
|
|
") )";
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Definition of operator ~sortBy~
|
||
|
|
|
||
|
|
*/
|
||
|
|
Operator ccrelsortby (
|
||
|
|
"sortby", // name
|
||
|
|
CcSortBySpec, // specification
|
||
|
|
CcSortBy<false>, // value mapping
|
||
|
|
Operator::SimpleSelect, // trivial selection function
|
||
|
|
CcSortByTypeMap // type mapping
|
||
|
|
);
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
7.3 Operator ~sort~
|
||
|
|
|
||
|
|
This operator sorts a stream of tuples lexicographically.
|
||
|
|
|
||
|
|
7.3.1 Type mapping function of operator ~sort~
|
||
|
|
|
||
|
|
Type mapping for ~sort~ is
|
||
|
|
|
||
|
|
---- ((stream (mtuple ((x1 t1)...(xn tn)))) -> (stream (mtuple ((x1 t1)...(xn tn)))
|
||
|
|
|
||
|
|
----
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<bool isSort> ListExpr
|
||
|
|
CcIdenticalTypeMap( ListExpr args )
|
||
|
|
{
|
||
|
|
ListExpr first;
|
||
|
|
const char* errorMessage = isSort ?
|
||
|
|
"Incorrect input for operator sort."
|
||
|
|
: "Incorrect input for operator rdup.";
|
||
|
|
|
||
|
|
if(nl->ListLength(args) == 1)
|
||
|
|
{
|
||
|
|
first = nl->First(args);
|
||
|
|
|
||
|
|
if((nl->ListLength(first) == 2 )
|
||
|
|
&& (CcTypeOfRelAlgSymbol(nl->First(first)) == mstream)
|
||
|
|
&& (CcTypeOfRelAlgSymbol(nl->First(nl->Second(first))) == mtuple)
|
||
|
|
&& CcIsTupleDescription(nl->Second(nl->Second(first)), nl))
|
||
|
|
{
|
||
|
|
return first;
|
||
|
|
}
|
||
|
|
ErrorReporter::ReportError(errorMessage);
|
||
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
||
|
|
}
|
||
|
|
ErrorReporter::ReportError(errorMessage);
|
||
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Specification of operator ~sort~
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string CcSortSpec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
||
|
|
"\"Example\" ) "
|
||
|
|
"( <text>((stream (mtuple([a1:d1, ... ,an:dn]"
|
||
|
|
")))) -> (stream (mtuple([a1:d1, ... ,an:dn])))"
|
||
|
|
"</text--->"
|
||
|
|
"<text>_ sort</text--->"
|
||
|
|
"<text>Sorts input stream lexicographically."
|
||
|
|
"</text--->"
|
||
|
|
"<text>query cities feed sort consume</text--->"
|
||
|
|
") )";
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Definition of operator ~sort~
|
||
|
|
|
||
|
|
*/
|
||
|
|
Operator ccrelsort (
|
||
|
|
"sort", // name
|
||
|
|
CcSortSpec, // specification
|
||
|
|
CcSortBy<true>, // value mapping
|
||
|
|
Operator::SimpleSelect, // trivial selection function
|
||
|
|
CcIdenticalTypeMap<true> // type mapping
|
||
|
|
);
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
7.3 Operator ~rdup~
|
||
|
|
|
||
|
|
This operator removes duplicates from a sorted stream.
|
||
|
|
|
||
|
|
4.1.2 Value mapping function of operator ~rdup~
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
static int
|
||
|
|
CcRdupValueMapping(Word* args, Word& result, int message,
|
||
|
|
Word& local, Supplier s)
|
||
|
|
{
|
||
|
|
Word tuple;
|
||
|
|
LexicographicalCcTupleCmp cmp;
|
||
|
|
CcTuple* currentTuple;
|
||
|
|
CcTuple* lastOutputTuple;
|
||
|
|
|
||
|
|
switch(message)
|
||
|
|
{
|
||
|
|
case OPEN:
|
||
|
|
qp->Open(args[0].addr);
|
||
|
|
local = SetWord(Address(0));
|
||
|
|
return 0;
|
||
|
|
case REQUEST:
|
||
|
|
while(true)
|
||
|
|
{
|
||
|
|
qp->Request(args[0].addr, tuple);
|
||
|
|
if(qp->Received(args[0].addr))
|
||
|
|
{
|
||
|
|
if(local.addr != 0)
|
||
|
|
{
|
||
|
|
currentTuple = (CcTuple*)tuple.addr;
|
||
|
|
lastOutputTuple = (CcTuple*)local.addr;
|
||
|
|
if(cmp(currentTuple, lastOutputTuple)
|
||
|
|
|| cmp(lastOutputTuple, currentTuple))
|
||
|
|
{
|
||
|
|
lastOutputTuple->DeleteIfAllowed();
|
||
|
|
local = SetWord(currentTuple->Clone());
|
||
|
|
result = SetWord(currentTuple);
|
||
|
|
return YIELD;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
currentTuple->DeleteIfAllowed();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
currentTuple = (CcTuple*)tuple.addr;
|
||
|
|
local = SetWord(currentTuple->Clone());
|
||
|
|
result = SetWord(currentTuple);
|
||
|
|
return YIELD;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
lastOutputTuple = (CcTuple*)local.addr;
|
||
|
|
if(lastOutputTuple != 0)
|
||
|
|
{
|
||
|
|
lastOutputTuple->DeleteIfAllowed();
|
||
|
|
}
|
||
|
|
return CANCEL;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
case CLOSE:
|
||
|
|
qp->Close(args[0].addr);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Specification of operator ~rdup~
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string CcRdupSpec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
||
|
|
"\"Example\" ) "
|
||
|
|
"( <text>((stream (mtuple([a1:d1, ... ,an:dn]))))"
|
||
|
|
" -> (stream (mtuple([a1:d1, ... ,an:dn])))"
|
||
|
|
"</text--->"
|
||
|
|
"<text>_ rdup</text--->"
|
||
|
|
"<text>Removes duplicates from a sorted "
|
||
|
|
"stream.</text--->"
|
||
|
|
"<text>query twenty feed ten feed concat sort "
|
||
|
|
"rdup consume</text--->"
|
||
|
|
") )";
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Definition of operator ~rdup~
|
||
|
|
|
||
|
|
*/
|
||
|
|
Operator ccrelrdup (
|
||
|
|
"rdup", // name
|
||
|
|
CcRdupSpec, // specification
|
||
|
|
CcRdupValueMapping, // value mapping
|
||
|
|
Operator::SimpleSelect, // trivial selection function
|
||
|
|
CcIdenticalTypeMap<false> // type mapping
|
||
|
|
);
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
7.3 Set Operators
|
||
|
|
|
||
|
|
These operators compute set operations on two sorted stream.
|
||
|
|
|
||
|
|
7.3.1 Generic Type Mapping for Set Operations
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
const char* ccSetOpErrorMessages[] =
|
||
|
|
{ "Incorrect input for operator mergesec.",
|
||
|
|
"Incorrect input for operator mergediff.",
|
||
|
|
"Incorrect input for operator mergeunion." };
|
||
|
|
|
||
|
|
template<int errorMessageIdx> ListExpr
|
||
|
|
CcSetOpTypeMap( ListExpr args )
|
||
|
|
{
|
||
|
|
ListExpr first, second;
|
||
|
|
|
||
|
|
if(nl->ListLength(args) == 2)
|
||
|
|
{
|
||
|
|
first = nl->First(args);
|
||
|
|
second = nl->Second(args);
|
||
|
|
|
||
|
|
if((nl->ListLength(first) == 2 )
|
||
|
|
&& (CcTypeOfRelAlgSymbol(nl->First(first)) == mstream)
|
||
|
|
&& (CcTypeOfRelAlgSymbol(nl->First(nl->Second(first))) == mtuple)
|
||
|
|
&& CcIsTupleDescription(nl->Second(nl->Second(first)), nl)
|
||
|
|
&& (nl->Equal(first, second)))
|
||
|
|
{
|
||
|
|
return first;
|
||
|
|
}
|
||
|
|
ErrorReporter::ReportError(ccSetOpErrorMessages[errorMessageIdx]);
|
||
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
||
|
|
}
|
||
|
|
ErrorReporter::ReportError(ccSetOpErrorMessages[errorMessageIdx]);
|
||
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
7.3.2 Auxiliary Class for Set Operations
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
class CcSetOperation
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
bool outputAWithoutB;
|
||
|
|
bool outputBWithoutA;
|
||
|
|
bool outputMatches;
|
||
|
|
|
||
|
|
private:
|
||
|
|
LexicographicalCcTupleCmp smallerThan;
|
||
|
|
|
||
|
|
Word streamA;
|
||
|
|
Word streamB;
|
||
|
|
|
||
|
|
CcTuple* currentATuple;
|
||
|
|
CcTuple* currentBTuple;
|
||
|
|
|
||
|
|
CcTuple* NextATuple(bool deleteOldTuple)
|
||
|
|
{
|
||
|
|
Word tuple;
|
||
|
|
if(deleteOldTuple && currentATuple != 0)
|
||
|
|
{
|
||
|
|
currentATuple->DeleteIfAllowed();
|
||
|
|
}
|
||
|
|
|
||
|
|
qp->Request(streamA.addr, tuple);
|
||
|
|
if(qp->Received(streamA.addr))
|
||
|
|
{
|
||
|
|
currentATuple = (CcTuple*)tuple.addr;
|
||
|
|
return currentATuple;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
currentATuple = 0;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
CcTuple* NextBTuple(bool deleteOldTuple)
|
||
|
|
{
|
||
|
|
Word tuple;
|
||
|
|
if(deleteOldTuple && currentBTuple != 0)
|
||
|
|
{
|
||
|
|
currentBTuple->DeleteIfAllowed();
|
||
|
|
}
|
||
|
|
|
||
|
|
qp->Request(streamB.addr, tuple);
|
||
|
|
if(qp->Received(streamB.addr))
|
||
|
|
{
|
||
|
|
currentBTuple = (CcTuple*)tuple.addr;
|
||
|
|
return currentBTuple;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
currentBTuple = 0;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
bool TuplesEqual(CcTuple* a, CcTuple* b)
|
||
|
|
{
|
||
|
|
return !(smallerThan(a, b) || smallerThan(b, a));
|
||
|
|
}
|
||
|
|
|
||
|
|
public:
|
||
|
|
|
||
|
|
CcSetOperation(Word streamA, Word streamB)
|
||
|
|
{
|
||
|
|
this->streamA = streamA;
|
||
|
|
this->streamB = streamB;
|
||
|
|
|
||
|
|
currentATuple = 0;
|
||
|
|
currentBTuple = 0;
|
||
|
|
|
||
|
|
qp->Open(streamA.addr);
|
||
|
|
qp->Open(streamB.addr);
|
||
|
|
|
||
|
|
NextATuple(false);
|
||
|
|
NextBTuple(false);
|
||
|
|
}
|
||
|
|
|
||
|
|
virtual ~CcSetOperation()
|
||
|
|
{
|
||
|
|
qp->Close(streamA.addr);
|
||
|
|
qp->Close(streamB.addr);
|
||
|
|
}
|
||
|
|
|
||
|
|
CcTuple* NextResultTuple()
|
||
|
|
{
|
||
|
|
CcTuple* result = 0;
|
||
|
|
while(result == 0)
|
||
|
|
{
|
||
|
|
if(currentATuple == 0)
|
||
|
|
{
|
||
|
|
if(currentBTuple == 0)
|
||
|
|
{
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
if(outputBWithoutA)
|
||
|
|
{
|
||
|
|
result = currentBTuple;
|
||
|
|
NextBTuple(false);
|
||
|
|
while(currentBTuple != 0 && TuplesEqual(result, currentBTuple))
|
||
|
|
{
|
||
|
|
NextBTuple(true);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
currentBTuple->DeleteIfAllowed();
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
if(currentBTuple == 0)
|
||
|
|
{
|
||
|
|
if(outputAWithoutB)
|
||
|
|
{
|
||
|
|
result = currentATuple;
|
||
|
|
NextATuple(false);
|
||
|
|
while(currentATuple != 0 && TuplesEqual(result, currentATuple))
|
||
|
|
{
|
||
|
|
NextATuple(true);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
currentATuple->DeleteIfAllowed();
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
/* both current tuples != 0 */
|
||
|
|
if(smallerThan(currentATuple, currentBTuple))
|
||
|
|
{
|
||
|
|
if(outputAWithoutB)
|
||
|
|
{
|
||
|
|
result = currentATuple;
|
||
|
|
}
|
||
|
|
|
||
|
|
CcTuple* tmp = currentATuple;
|
||
|
|
NextATuple(false);
|
||
|
|
while(currentATuple != 0 && TuplesEqual(tmp, currentATuple))
|
||
|
|
{
|
||
|
|
NextATuple(true);
|
||
|
|
}
|
||
|
|
if(!outputAWithoutB)
|
||
|
|
{
|
||
|
|
tmp->DeleteIfAllowed();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else if(smallerThan(currentBTuple, currentATuple))
|
||
|
|
{
|
||
|
|
if(outputBWithoutA)
|
||
|
|
{
|
||
|
|
result = currentBTuple;
|
||
|
|
}
|
||
|
|
|
||
|
|
CcTuple* tmp = currentBTuple;
|
||
|
|
NextBTuple(false);
|
||
|
|
while(currentBTuple != 0 && TuplesEqual(tmp, currentBTuple))
|
||
|
|
{
|
||
|
|
NextBTuple(true);
|
||
|
|
}
|
||
|
|
if(!outputBWithoutA)
|
||
|
|
{
|
||
|
|
tmp->DeleteIfAllowed();
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
/* found match */
|
||
|
|
assert(TuplesEqual(currentATuple, currentBTuple));
|
||
|
|
CcTuple* match = currentATuple;
|
||
|
|
if(outputMatches)
|
||
|
|
{
|
||
|
|
result = match;
|
||
|
|
}
|
||
|
|
|
||
|
|
NextATuple(false);
|
||
|
|
while(currentATuple != 0 && TuplesEqual(match, currentATuple))
|
||
|
|
{
|
||
|
|
NextATuple(true);
|
||
|
|
}
|
||
|
|
while(currentBTuple != 0 && TuplesEqual(match, currentBTuple))
|
||
|
|
{
|
||
|
|
NextBTuple(true);
|
||
|
|
}
|
||
|
|
if(!outputMatches)
|
||
|
|
{
|
||
|
|
match->DeleteIfAllowed();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
7.3.2 Generic Value Mapping Function for Set Operations
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
template<bool outputAWithoutB, bool outputBWithoutA, bool outputMatches>
|
||
|
|
int
|
||
|
|
CcSetOpValueMapping(Word* args, Word& result, int message,
|
||
|
|
Word& local, Supplier s)
|
||
|
|
{
|
||
|
|
CcSetOperation* localInfo;
|
||
|
|
|
||
|
|
switch(message)
|
||
|
|
{
|
||
|
|
case OPEN:
|
||
|
|
localInfo = new CcSetOperation(args[0], args[1]);
|
||
|
|
localInfo->outputBWithoutA = outputBWithoutA;
|
||
|
|
localInfo->outputAWithoutB = outputAWithoutB;
|
||
|
|
localInfo->outputMatches = outputMatches;
|
||
|
|
|
||
|
|
local = SetWord(localInfo);
|
||
|
|
return 0;
|
||
|
|
case REQUEST:
|
||
|
|
localInfo = (CcSetOperation*)local.addr;
|
||
|
|
result = SetWord(localInfo->NextResultTuple());
|
||
|
|
return result.addr != 0 ? YIELD : CANCEL;
|
||
|
|
case CLOSE:
|
||
|
|
localInfo = (CcSetOperation*)local.addr;
|
||
|
|
if(localInfo)
|
||
|
|
{
|
||
|
|
delete localInfo;
|
||
|
|
local = SetWord(Address(0));
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Specification of Operator ~mergesec~
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string CcMergeSecSpec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
||
|
|
"\"Example\" ) "
|
||
|
|
"( <text>((stream (mtuple ((x1 t1) ... "
|
||
|
|
"(xn tn)))) stream (mtuple ((x1 t1) ... (xn tn)"
|
||
|
|
")))) -> (stream (mtuple ((x1 t1) ... (xn tn))))"
|
||
|
|
"</text--->"
|
||
|
|
"<text>_ _ mergesec</text--->"
|
||
|
|
"<text>Computes the intersection of two sorted "
|
||
|
|
"streams.</text--->"
|
||
|
|
"<text>query twenty feed oddtwenty feed mergesec"
|
||
|
|
" consume</text--->"
|
||
|
|
") )";
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Definition of Operator ~mergesec~
|
||
|
|
|
||
|
|
*/
|
||
|
|
Operator ccrelmergesec(
|
||
|
|
"mergesec", // name
|
||
|
|
CcMergeSecSpec, // specification
|
||
|
|
CcSetOpValueMapping<false, false, true>, // value mapping
|
||
|
|
Operator::SimpleSelect, // trivial selection function
|
||
|
|
CcSetOpTypeMap<0> // type mapping
|
||
|
|
);
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Specification of Operator ~mergediff~
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string CcMergeDiffSpec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
||
|
|
"\"Example\" ) "
|
||
|
|
"( <text>((stream (mtuple ((x1 t1) ... (xn tn)"
|
||
|
|
"))) stream (mtuple ((x1 t1) ... (xn tn))))) ->"
|
||
|
|
" (stream (mtuple ((x1 t1) ... (xn tn))))"
|
||
|
|
"</text--->"
|
||
|
|
"<text>_ _ mergediff</text--->"
|
||
|
|
"<text>Computes the difference of two sorted "
|
||
|
|
"streams.</text--->"
|
||
|
|
"<text>query twenty feed oddtwenty feed"
|
||
|
|
" mergediff consume</text--->"
|
||
|
|
") )";
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Definition of Operator ~mergediff~
|
||
|
|
|
||
|
|
*/
|
||
|
|
Operator ccrelmergediff(
|
||
|
|
"mergediff", // name
|
||
|
|
CcMergeDiffSpec, // specification
|
||
|
|
CcSetOpValueMapping<true, false, false>, // value mapping
|
||
|
|
Operator::SimpleSelect, // trivial selection function
|
||
|
|
CcSetOpTypeMap<1> // type mapping
|
||
|
|
);
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Specification of Operator ~mergeunion~
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string CcMergeUnionSpec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
||
|
|
"\"Example\" ) "
|
||
|
|
"( <text>((stream (mtuple ((x1 t1) ... (xn tn))))"
|
||
|
|
"stream (mtuple ((x1 t1) ... (xn tn))))) -> (stream"
|
||
|
|
" (mtuple ((x1 t1) ... (xn tn))))</text--->"
|
||
|
|
"<text>_ _ mergeunion</text--->"
|
||
|
|
"<text>Computes the union of two sorted streams."
|
||
|
|
"</text--->"
|
||
|
|
"<text>query twenty feed oddtwenty feed "
|
||
|
|
"mergeunion consume</text--->"
|
||
|
|
") )";
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Definition of Operator ~mergeunion~
|
||
|
|
|
||
|
|
*/
|
||
|
|
Operator ccrelmergeunion(
|
||
|
|
"mergeunion", // name
|
||
|
|
CcMergeUnionSpec, // specification
|
||
|
|
CcSetOpValueMapping<true, true, true>, // value mapping
|
||
|
|
Operator::SimpleSelect, // trivial selection function
|
||
|
|
CcSetOpTypeMap<2> // type mapping
|
||
|
|
);
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
7.3 Operator ~mergejoin~
|
||
|
|
|
||
|
|
This operator computes the equijoin two streams.
|
||
|
|
|
||
|
|
7.3.1 Type mapping function of operators ~mergejoin~ and ~hashjoin~
|
||
|
|
|
||
|
|
Type mapping for ~mergejoin~ is
|
||
|
|
|
||
|
|
---- ((stream (mtuple ((x1 t1) ... (xn tn)))) (stream (mtuple ((y1 d1) ... (ym dm)))) xi yj)
|
||
|
|
|
||
|
|
-> (stream (mtuple ((x1 t1) ... (xn tn) (y1 d1) ... (ym dm)))) APPEND (i j)
|
||
|
|
----
|
||
|
|
|
||
|
|
Type mapping for ~hashjoin~ is
|
||
|
|
|
||
|
|
---- ((stream (mtuple ((x1 t1) ... (xn tn)))) (stream (mtuple ((y1 d1) ... (ym dm)))) xi yj int)
|
||
|
|
|
||
|
|
-> (stream (mtuple ((x1 t1) ... (xn tn) (y1 d1) ... (ym dm)))) APPEND (i j)
|
||
|
|
----
|
||
|
|
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
const char* ccJoinErrorMessages[] =
|
||
|
|
{ "Incorrect input for operator mergejoin.",
|
||
|
|
"Incorrect input for operator sortmergejoin.",
|
||
|
|
"Incorrect input for operator hashjoin." };
|
||
|
|
|
||
|
|
template<bool expectIntArgument, int errorMessageIdx>
|
||
|
|
ListExpr
|
||
|
|
CcJoinTypeMap(ListExpr args)
|
||
|
|
{
|
||
|
|
ListExpr attrTypeA, attrTypeB;
|
||
|
|
ListExpr streamA, streamB, list, list1, list2, outlist;
|
||
|
|
if (nl->ListLength(args) == (expectIntArgument ? 5 : 4))
|
||
|
|
{
|
||
|
|
streamA = nl->First(args); streamB = nl->Second(args);
|
||
|
|
if (nl->ListLength(streamA) == 2)
|
||
|
|
{
|
||
|
|
if (CcTypeOfRelAlgSymbol(nl->First(streamA)) == mstream)
|
||
|
|
{
|
||
|
|
if (nl->ListLength(nl->Second(streamA)) == 2)
|
||
|
|
{
|
||
|
|
if (CcTypeOfRelAlgSymbol(nl->First(nl->Second(streamA))) == mtuple)
|
||
|
|
{
|
||
|
|
list1 = nl->Second(nl->Second(streamA));
|
||
|
|
}
|
||
|
|
else goto typeerror;
|
||
|
|
}
|
||
|
|
else goto typeerror;
|
||
|
|
}
|
||
|
|
else goto typeerror;
|
||
|
|
}
|
||
|
|
else goto typeerror;
|
||
|
|
|
||
|
|
if (nl->ListLength(streamB) == 2)
|
||
|
|
{
|
||
|
|
if (CcTypeOfRelAlgSymbol(nl->First(streamB)) == mstream)
|
||
|
|
{
|
||
|
|
if (nl->ListLength(nl->Second(streamB)) == 2)
|
||
|
|
{
|
||
|
|
if (CcTypeOfRelAlgSymbol(nl->First(nl->Second(streamB))) == mtuple)
|
||
|
|
{
|
||
|
|
list2 = nl->Second(nl->Second(streamB));
|
||
|
|
}
|
||
|
|
else goto typeerror;
|
||
|
|
}
|
||
|
|
else goto typeerror;
|
||
|
|
}
|
||
|
|
else goto typeerror;
|
||
|
|
}
|
||
|
|
else goto typeerror;
|
||
|
|
|
||
|
|
if(!CcAttributesAreDisjoint(list1, list2))
|
||
|
|
{
|
||
|
|
goto typeerror;
|
||
|
|
}
|
||
|
|
|
||
|
|
list = CcConcatLists(list1, list2);
|
||
|
|
outlist = nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()),
|
||
|
|
nl->TwoElemList(nl->SymbolAtom(CcTuple::BasicType()), list));
|
||
|
|
|
||
|
|
ListExpr joinAttrDescription;
|
||
|
|
if(!(nl->IsAtom(nl->Third(args))
|
||
|
|
&& nl->IsAtom(nl->Fourth(args))
|
||
|
|
&& nl->AtomType(nl->Third(args)) == SymbolType
|
||
|
|
&& nl->AtomType(nl->Fourth(args)) == SymbolType))
|
||
|
|
{
|
||
|
|
goto typeerror;
|
||
|
|
}
|
||
|
|
|
||
|
|
string attrAName = nl->SymbolValue(nl->Third(args));
|
||
|
|
string attrBName = nl->SymbolValue(nl->Fourth(args));
|
||
|
|
int attrAIndex = CcFindAttribute(nl->Second(nl->Second(streamA)),
|
||
|
|
attrAName, attrTypeA, nl);
|
||
|
|
int attrBIndex = CcFindAttribute(nl->Second(nl->Second(streamB)),
|
||
|
|
attrBName, attrTypeB, nl);
|
||
|
|
if(attrAIndex <= 0 || attrBIndex <= 0 ||
|
||
|
|
!nl->Equal(attrTypeA, attrTypeB))
|
||
|
|
{
|
||
|
|
goto typeerror;
|
||
|
|
}
|
||
|
|
|
||
|
|
if(expectIntArgument &&
|
||
|
|
nl->SymbolValue(nl->Fifth(args)) != CcInt::BasicType())
|
||
|
|
{
|
||
|
|
goto typeerror;
|
||
|
|
}
|
||
|
|
|
||
|
|
joinAttrDescription =
|
||
|
|
nl->TwoElemList(nl->IntAtom(attrAIndex),
|
||
|
|
nl->IntAtom(attrBIndex));
|
||
|
|
return nl->ThreeElemList(nl->SymbolAtom(Symbol::APPEND()),
|
||
|
|
joinAttrDescription, outlist);
|
||
|
|
}
|
||
|
|
else goto typeerror;
|
||
|
|
|
||
|
|
typeerror:
|
||
|
|
ErrorReporter::ReportError(ccJoinErrorMessages[errorMessageIdx]);
|
||
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.2 Auxiliary definitions for value mapping function of operator ~mergejoin~
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
static CcInt oneCcInt(true, 1);
|
||
|
|
static CcBool trueCcBool(true, true);
|
||
|
|
|
||
|
|
CPUTimeMeasurer ccMergeMeasurer;
|
||
|
|
|
||
|
|
class CcMergeJoinLocalInfo
|
||
|
|
{
|
||
|
|
private:
|
||
|
|
vector<CcTuple*> bucketA;
|
||
|
|
vector<CcTuple*> bucketB;
|
||
|
|
deque<CcTuple*> resultBucket;
|
||
|
|
|
||
|
|
Word aResult;
|
||
|
|
Word bResult;
|
||
|
|
|
||
|
|
Word streamALocalInfo;
|
||
|
|
Word streamBLocalInfo;
|
||
|
|
|
||
|
|
Word streamA;
|
||
|
|
Word streamB;
|
||
|
|
|
||
|
|
ArgVector aArgs;
|
||
|
|
ArgVector bArgs;
|
||
|
|
|
||
|
|
int attrIndexA;
|
||
|
|
int attrIndexB;
|
||
|
|
|
||
|
|
bool expectSorted;
|
||
|
|
|
||
|
|
int CompareCcTuples(CcTuple* a, CcTuple* b)
|
||
|
|
{
|
||
|
|
/* tuples with NULL-Values in the join attributes
|
||
|
|
are never matched with other tuples. */
|
||
|
|
if(!((Attribute*)a->Get(attrIndexA))->IsDefined())
|
||
|
|
{
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
if(!((Attribute*)b->Get(attrIndexB))->IsDefined())
|
||
|
|
{
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
return ((Attribute*)a->Get(attrIndexA))->
|
||
|
|
Compare((Attribute*)b->Get(attrIndexB));
|
||
|
|
}
|
||
|
|
|
||
|
|
void SetArgs(ArgVector& args, Word stream, Word attrIndex)
|
||
|
|
{
|
||
|
|
args[0] = SetWord(stream.addr);
|
||
|
|
args[2] = SetWord(&oneCcInt);
|
||
|
|
args[3] = SetWord(attrIndex.addr);
|
||
|
|
args[4] = SetWord(&trueCcBool);
|
||
|
|
}
|
||
|
|
|
||
|
|
CcTuple* nextATuple()
|
||
|
|
{
|
||
|
|
bool yield;
|
||
|
|
if(expectSorted)
|
||
|
|
{
|
||
|
|
qp->Request(streamA.addr, aResult);
|
||
|
|
yield = qp->Received(streamA.addr);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
int errorCode =
|
||
|
|
CcSortBy<false>(aArgs, aResult, REQUEST, streamALocalInfo, 0);
|
||
|
|
yield = (errorCode == YIELD);
|
||
|
|
}
|
||
|
|
|
||
|
|
if(yield)
|
||
|
|
{
|
||
|
|
return (CcTuple*)aResult.addr;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
aResult = SetWord((void*)0);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
CcTuple* nextBTuple()
|
||
|
|
{
|
||
|
|
bool yield;
|
||
|
|
if(expectSorted)
|
||
|
|
{
|
||
|
|
qp->Request(streamB.addr, bResult);
|
||
|
|
yield = qp->Received(streamB.addr);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
int errorCode =
|
||
|
|
CcSortBy<false>(bArgs, bResult, REQUEST, streamBLocalInfo, 0);
|
||
|
|
yield = (errorCode == YIELD);
|
||
|
|
}
|
||
|
|
|
||
|
|
if(yield)
|
||
|
|
{
|
||
|
|
return (CcTuple*)bResult.addr;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
bResult = SetWord((void*)0);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
bool FetchNextMatch()
|
||
|
|
{
|
||
|
|
CcTuple* aCcTuple = (CcTuple*)aResult.addr;
|
||
|
|
CcTuple* bCcTuple = (CcTuple*)bResult.addr;
|
||
|
|
if(aCcTuple == 0 || bCcTuple == 0)
|
||
|
|
{
|
||
|
|
if(aCcTuple != 0)
|
||
|
|
aCcTuple->DeleteIfAllowed();
|
||
|
|
if(bCcTuple != 0)
|
||
|
|
bCcTuple->DeleteIfAllowed();
|
||
|
|
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
int cmpResult =
|
||
|
|
CompareCcTuples((CcTuple*)aResult.addr, (CcTuple*)bResult.addr);
|
||
|
|
while(cmpResult != 0)
|
||
|
|
{
|
||
|
|
if(cmpResult < 0)
|
||
|
|
{
|
||
|
|
((CcTuple*)aResult.addr)->DeleteIfAllowed();
|
||
|
|
if(nextATuple() == 0)
|
||
|
|
{
|
||
|
|
((CcTuple*)bResult.addr)->DeleteIfAllowed();
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
((CcTuple*)bResult.addr)->DeleteIfAllowed();
|
||
|
|
if(nextBTuple() == 0)
|
||
|
|
{
|
||
|
|
((CcTuple*)aResult.addr)->DeleteIfAllowed();
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
cmpResult =
|
||
|
|
CompareCcTuples((CcTuple*)aResult.addr, (CcTuple*)bResult.addr);
|
||
|
|
}
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void ComputeProductOfBuckets()
|
||
|
|
{
|
||
|
|
assert(!bucketA.empty());
|
||
|
|
assert(!bucketB.empty());
|
||
|
|
|
||
|
|
vector<CcTuple*>::iterator iterA = bucketA.begin();
|
||
|
|
vector<CcTuple*>::iterator iterB = bucketB.begin();
|
||
|
|
for(; iterA != bucketA.end(); iterA++)
|
||
|
|
{
|
||
|
|
for(iterB = bucketB.begin(); iterB != bucketB.end(); iterB++)
|
||
|
|
{
|
||
|
|
CcTuple* resultTuple = new CcTuple;
|
||
|
|
resultTuple->SetFree(true);
|
||
|
|
Word resultWord = SetWord(resultTuple);
|
||
|
|
Word aWord = SetWord(*iterA);
|
||
|
|
Word bWord = SetWord(*iterB);
|
||
|
|
CcConcat(aWord, bWord, resultWord);
|
||
|
|
resultBucket.push_back(resultTuple);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void ClearBuckets()
|
||
|
|
{
|
||
|
|
vector<CcTuple*>::iterator iterA = bucketA.begin();
|
||
|
|
vector<CcTuple*>::iterator iterB = bucketB.begin();
|
||
|
|
|
||
|
|
for(; iterA != bucketA.end(); iterA++)
|
||
|
|
{
|
||
|
|
(*iterA)->DeleteIfAllowed();
|
||
|
|
}
|
||
|
|
|
||
|
|
for(; iterB != bucketB.end(); iterB++)
|
||
|
|
{
|
||
|
|
(*iterB)->DeleteIfAllowed();
|
||
|
|
}
|
||
|
|
|
||
|
|
bucketA.clear();
|
||
|
|
bucketB.clear();
|
||
|
|
}
|
||
|
|
|
||
|
|
void FillResultBucket()
|
||
|
|
{
|
||
|
|
assert((CcTuple*)aResult.addr != 0);
|
||
|
|
assert((CcTuple*)bResult.addr != 0);
|
||
|
|
|
||
|
|
CcTuple* aMatch = (CcTuple*)aResult.addr;
|
||
|
|
CcTuple* bMatch = (CcTuple*)bResult.addr;
|
||
|
|
assert(CompareCcTuples(aMatch, bMatch) == 0);
|
||
|
|
|
||
|
|
CcTuple* currentA = aMatch;
|
||
|
|
CcTuple* currentB = bMatch;
|
||
|
|
|
||
|
|
while(currentA != 0 && CompareCcTuples(currentA, bMatch) == 0)
|
||
|
|
{
|
||
|
|
bucketA.push_back(currentA);
|
||
|
|
currentA = nextATuple();
|
||
|
|
}
|
||
|
|
|
||
|
|
while(currentB != 0 && CompareCcTuples(aMatch, currentB) == 0)
|
||
|
|
{
|
||
|
|
bucketB.push_back(currentB);
|
||
|
|
currentB = nextBTuple();
|
||
|
|
}
|
||
|
|
|
||
|
|
ComputeProductOfBuckets();
|
||
|
|
ClearBuckets();
|
||
|
|
}
|
||
|
|
|
||
|
|
public:
|
||
|
|
CcMergeJoinLocalInfo(Word streamA, Word attrIndexA,
|
||
|
|
Word streamB, Word attrIndexB, bool expectSorted)
|
||
|
|
{
|
||
|
|
assert(streamA.addr != 0);
|
||
|
|
assert(streamB.addr != 0);
|
||
|
|
assert(attrIndexA.addr != 0);
|
||
|
|
assert(attrIndexB.addr != 0);
|
||
|
|
assert(((CcInt*)attrIndexA.addr)->GetIntval() > 0);
|
||
|
|
assert(((CcInt*)attrIndexB.addr)->GetIntval() > 0);
|
||
|
|
|
||
|
|
aResult = SetWord(Address(0));
|
||
|
|
bResult = SetWord(Address(0));
|
||
|
|
|
||
|
|
this->expectSorted = expectSorted;
|
||
|
|
this->streamA = streamA;
|
||
|
|
this->streamB = streamB;
|
||
|
|
this->attrIndexA = ((CcInt*)attrIndexA.addr)->GetIntval() - 1;
|
||
|
|
this->attrIndexB = ((CcInt*)attrIndexB.addr)->GetIntval() - 1;
|
||
|
|
|
||
|
|
if(expectSorted)
|
||
|
|
{
|
||
|
|
qp->Open(streamA.addr);
|
||
|
|
qp->Open(streamB.addr);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
SetArgs(aArgs, streamA, attrIndexA);
|
||
|
|
SetArgs(bArgs, streamB, attrIndexB);
|
||
|
|
CcSortBy<false>(aArgs, aResult, OPEN, streamALocalInfo, 0);
|
||
|
|
CcSortBy<false>(bArgs, bResult, OPEN, streamBLocalInfo, 0);
|
||
|
|
}
|
||
|
|
|
||
|
|
nextATuple();
|
||
|
|
nextBTuple();
|
||
|
|
}
|
||
|
|
|
||
|
|
~CcMergeJoinLocalInfo()
|
||
|
|
{
|
||
|
|
if(expectSorted)
|
||
|
|
{
|
||
|
|
qp->Close(streamA.addr);
|
||
|
|
qp->Close(streamB.addr);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
CcSortBy<false>(aArgs, aResult, CLOSE, streamALocalInfo, 0);
|
||
|
|
CcSortBy<false>(bArgs, bResult, CLOSE, streamBLocalInfo, 0);
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
CcTuple* NextResultTuple()
|
||
|
|
{
|
||
|
|
if(resultBucket.empty())
|
||
|
|
{
|
||
|
|
if(FetchNextMatch())
|
||
|
|
{
|
||
|
|
FillResultBucket();
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
CcTuple* next = resultBucket.front();
|
||
|
|
resultBucket.pop_front();
|
||
|
|
return next;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.2 Value mapping function of operator ~mergejoin~
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
template<bool expectSorted> int
|
||
|
|
CcMergeJoin(Word* args, Word& result, int message, Word& local, Supplier s)
|
||
|
|
{
|
||
|
|
CcMergeJoinLocalInfo* localInfo;
|
||
|
|
|
||
|
|
switch(message)
|
||
|
|
{
|
||
|
|
case OPEN:
|
||
|
|
localInfo = new CcMergeJoinLocalInfo
|
||
|
|
(args[0], args[4], args[1], args[5], expectSorted);
|
||
|
|
local = SetWord(localInfo);
|
||
|
|
return 0;
|
||
|
|
case REQUEST:
|
||
|
|
ccMergeMeasurer.Enter();
|
||
|
|
localInfo = (CcMergeJoinLocalInfo*)local.addr;
|
||
|
|
result = SetWord(localInfo->NextResultTuple());
|
||
|
|
ccMergeMeasurer.Exit();
|
||
|
|
return result.addr != 0 ? YIELD : CANCEL;
|
||
|
|
case CLOSE:
|
||
|
|
ccMergeMeasurer.PrintCPUTimeAndReset("CPU Time for Merging Tuples : ");
|
||
|
|
|
||
|
|
localInfo = (CcMergeJoinLocalInfo*)local.addr;
|
||
|
|
if(localInfo)
|
||
|
|
{
|
||
|
|
delete localInfo;
|
||
|
|
local = SetWord(Address(0));
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Specification of operator ~mergejoin~
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string CcMergeJoinSpec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
||
|
|
"\"Example\" ) "
|
||
|
|
"( <text>((stream (mtuple ((x1 t1) ... "
|
||
|
|
"(xn tn)))) (stream (mtuple ((y1 d1) ... "
|
||
|
|
"(ym dm)))) xi yj) -> (stream (mtuple ((x1 t1)"
|
||
|
|
" ... (xn tn) (y1 d1) ... (ym dm))))"
|
||
|
|
"</text--->"
|
||
|
|
"<text>_ _ mergejoin [_, _]</text--->"
|
||
|
|
"<text>Computes the equijoin two streams. "
|
||
|
|
"Expects that input streams are sorted."
|
||
|
|
"</text--->"
|
||
|
|
"<text>query duplicates feed ten feed "
|
||
|
|
"rename[A] mergejoin[no, no_A] sort rdup "
|
||
|
|
"consume</text--->"
|
||
|
|
") )";
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Definition of operator ~mergejoin~
|
||
|
|
|
||
|
|
*/
|
||
|
|
Operator ccrelmergejoin (
|
||
|
|
"mergejoin", // name
|
||
|
|
CcMergeJoinSpec, // specification
|
||
|
|
CcMergeJoin<true>, // value mapping
|
||
|
|
Operator::SimpleSelect, // trivial selection function
|
||
|
|
CcJoinTypeMap<false, 0> // type mapping
|
||
|
|
);
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
7.3 Operator ~sortmergejoin~
|
||
|
|
|
||
|
|
This operator sorts two input streams and computes their equijoin.
|
||
|
|
|
||
|
|
4.1.3 Specification of operator ~sortmergejoin~
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string CcSortMergeJoinSpec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" "
|
||
|
|
"\"Meaning\" \"Example\" ) "
|
||
|
|
"( <text>((stream (mtuple ((x1 t1) ... "
|
||
|
|
"(xn tn)))) (stream (mtuple ((y1 d1) ..."
|
||
|
|
" (ym dm)))) xi yj) -> (stream (mtuple "
|
||
|
|
"((x1 t1) ... (xn tn) (y1 d1) ... (ym dm)"
|
||
|
|
")))</text--->"
|
||
|
|
"<text>_ _ sortmergejoin [ _ , _ ]"
|
||
|
|
"</text--->"
|
||
|
|
"<text>Computes the equijoin two streams."
|
||
|
|
"</text--->"
|
||
|
|
"<text>query duplicates feed ten feed "
|
||
|
|
"mergejoin[no, nr] consume</text--->"
|
||
|
|
") )";
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Definition of operator ~sortmergejoin~
|
||
|
|
|
||
|
|
*/
|
||
|
|
Operator ccrelsortmergejoin (
|
||
|
|
"sortmergejoin", // name
|
||
|
|
CcSortMergeJoinSpec, // specification
|
||
|
|
CcMergeJoin<false>, // value mapping
|
||
|
|
Operator::SimpleSelect, // trivial selection function
|
||
|
|
CcJoinTypeMap<false, 1> // type mapping
|
||
|
|
);
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
7.3 Operator ~hashjoin~
|
||
|
|
|
||
|
|
This operator computes the equijoin two streams via a hash join.
|
||
|
|
The user can specify the number of hash buckets.
|
||
|
|
|
||
|
|
7.3.1 Auxiliary Class for Operator ~hashjoin~
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
CPUTimeMeasurer ccHashMeasurer;
|
||
|
|
// measures cost of distributing into buckets and
|
||
|
|
// of computing products of buckets
|
||
|
|
CPUTimeMeasurer ccBucketMeasurer;
|
||
|
|
// measures the cost of producing the tuples in
|
||
|
|
// the result set
|
||
|
|
|
||
|
|
class CcHashJoinLocalInfo
|
||
|
|
{
|
||
|
|
private:
|
||
|
|
static const size_t MAX_BUCKETS = 6151;
|
||
|
|
static const size_t MIN_BUCKETS = 1;
|
||
|
|
static const size_t DEFAULT_BUCKETS = 97;
|
||
|
|
size_t nBuckets;
|
||
|
|
size_t currentBucket;
|
||
|
|
|
||
|
|
int attrIndexA;
|
||
|
|
int attrIndexB;
|
||
|
|
|
||
|
|
Word streamA;
|
||
|
|
Word streamB;
|
||
|
|
|
||
|
|
vector<vector< CcTuple*> > bucketsA;
|
||
|
|
vector<vector< CcTuple*> > bucketsB;
|
||
|
|
vector<CcTuple*> resultBucket;
|
||
|
|
|
||
|
|
int CompareCcTuples(CcTuple* a, CcTuple* b)
|
||
|
|
{
|
||
|
|
/* tuples with NULL-Values in the join attributes
|
||
|
|
are never matched with other tuples. */
|
||
|
|
if(!((Attribute*)a->Get(attrIndexA))->IsDefined())
|
||
|
|
{
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
if(!((Attribute*)b->Get(attrIndexB))->IsDefined())
|
||
|
|
{
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
return ((Attribute*)a->Get(attrIndexA))->
|
||
|
|
Compare((Attribute*)b->Get(attrIndexB));
|
||
|
|
}
|
||
|
|
|
||
|
|
size_t HashTuple(CcTuple* tuple, int attrIndex)
|
||
|
|
{
|
||
|
|
return (((Attribute*)tuple->Get(attrIndex))->
|
||
|
|
HashValue() % nBuckets);
|
||
|
|
}
|
||
|
|
|
||
|
|
void FillHashBuckets(Word stream, int attrIndex,
|
||
|
|
vector<vector< CcTuple*> >& buckets)
|
||
|
|
{
|
||
|
|
Word tupleWord;
|
||
|
|
qp->Open(stream.addr);
|
||
|
|
qp->Request(stream.addr, tupleWord);
|
||
|
|
while(qp->Received(stream.addr))
|
||
|
|
{
|
||
|
|
ccHashMeasurer.Enter();
|
||
|
|
|
||
|
|
CcTuple* tuple = (CcTuple*)tupleWord.addr;
|
||
|
|
buckets[HashTuple(tuple, attrIndex)].push_back(tuple);
|
||
|
|
|
||
|
|
ccHashMeasurer.Exit();
|
||
|
|
|
||
|
|
qp->Request(stream.addr, tupleWord);
|
||
|
|
}
|
||
|
|
qp->Close(stream.addr);
|
||
|
|
}
|
||
|
|
|
||
|
|
void ClearBucket(vector<CcTuple*>& bucket)
|
||
|
|
{
|
||
|
|
vector<CcTuple*>::iterator iter = bucket.begin();
|
||
|
|
while(iter != bucket.end())
|
||
|
|
{
|
||
|
|
(*iter)->DeleteIfAllowed();
|
||
|
|
iter++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
bool FillResultBucket()
|
||
|
|
{
|
||
|
|
ccHashMeasurer.Enter();
|
||
|
|
|
||
|
|
while(resultBucket.empty() && currentBucket < nBuckets)
|
||
|
|
{
|
||
|
|
vector<CcTuple*>& a = bucketsA[currentBucket];
|
||
|
|
vector<CcTuple*>& b = bucketsB[currentBucket];
|
||
|
|
|
||
|
|
vector<CcTuple*>::iterator iterA = a.begin();
|
||
|
|
vector<CcTuple*>::iterator iterB;
|
||
|
|
for(; iterA != a.end(); iterA++)
|
||
|
|
{
|
||
|
|
for(iterB = b.begin(); iterB != b.end(); iterB++)
|
||
|
|
{
|
||
|
|
if(CompareCcTuples(*iterA, *iterB) == 0)
|
||
|
|
{
|
||
|
|
ccHashMeasurer.Exit();
|
||
|
|
ccBucketMeasurer.Enter();
|
||
|
|
|
||
|
|
CcTuple* resultTuple = new CcTuple;
|
||
|
|
resultTuple->SetFree(true);
|
||
|
|
Word resultWord = SetWord(resultTuple);
|
||
|
|
Word aWord = SetWord(*iterA);
|
||
|
|
Word bWord = SetWord(*iterB);
|
||
|
|
CcConcat(aWord, bWord, resultWord);
|
||
|
|
resultBucket.push_back(resultTuple);
|
||
|
|
|
||
|
|
ccBucketMeasurer.Exit();
|
||
|
|
ccHashMeasurer.Enter();
|
||
|
|
};
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
ClearBucket(a);
|
||
|
|
ClearBucket(b);
|
||
|
|
currentBucket++;
|
||
|
|
}
|
||
|
|
|
||
|
|
ccHashMeasurer.Exit();
|
||
|
|
return !resultBucket.empty();
|
||
|
|
};
|
||
|
|
|
||
|
|
public:
|
||
|
|
CcHashJoinLocalInfo(Word streamA, Word attrIndexAWord,
|
||
|
|
Word streamB, Word attrIndexBWord, Word nBucketsWord)
|
||
|
|
{
|
||
|
|
this->streamA = streamA;
|
||
|
|
this->streamB = streamB;
|
||
|
|
currentBucket = 0;
|
||
|
|
|
||
|
|
attrIndexA = ((CcInt*)attrIndexAWord.addr)->GetIntval() - 1;
|
||
|
|
attrIndexB = ((CcInt*)attrIndexBWord.addr)->GetIntval() - 1;
|
||
|
|
nBuckets = ((CcInt*)nBucketsWord.addr)->GetIntval();
|
||
|
|
if(nBuckets < MIN_BUCKETS)
|
||
|
|
{
|
||
|
|
nBuckets = MIN_BUCKETS;
|
||
|
|
}
|
||
|
|
else if(nBuckets > MAX_BUCKETS)
|
||
|
|
{
|
||
|
|
nBuckets = MAX_BUCKETS;
|
||
|
|
}
|
||
|
|
|
||
|
|
ccHashMeasurer.Enter();
|
||
|
|
|
||
|
|
bucketsA.resize(nBuckets);
|
||
|
|
bucketsB.resize(nBuckets);
|
||
|
|
|
||
|
|
ccHashMeasurer.Exit();
|
||
|
|
|
||
|
|
FillHashBuckets(streamA, attrIndexA, bucketsA);
|
||
|
|
FillHashBuckets(streamB, attrIndexB, bucketsB);
|
||
|
|
}
|
||
|
|
|
||
|
|
~CcHashJoinLocalInfo()
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
CcTuple* NextResultTuple()
|
||
|
|
{
|
||
|
|
if(resultBucket.empty())
|
||
|
|
{
|
||
|
|
if(!FillResultBucket())
|
||
|
|
{
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
CcTuple* result = resultBucket.back();
|
||
|
|
resultBucket.pop_back();
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
7.3.2 Value Mapping Function of Operator ~hashjoin~
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
static int
|
||
|
|
CcHashJoin(Word* args, Word& result, int message, Word& local, Supplier s)
|
||
|
|
{
|
||
|
|
CcHashJoinLocalInfo* localInfo;
|
||
|
|
|
||
|
|
switch(message)
|
||
|
|
{
|
||
|
|
case OPEN:
|
||
|
|
localInfo =
|
||
|
|
new CcHashJoinLocalInfo(args[0], args[5], args[1], args[6], args[4]);
|
||
|
|
local = SetWord(localInfo);
|
||
|
|
return 0;
|
||
|
|
case REQUEST:
|
||
|
|
localInfo = (CcHashJoinLocalInfo*)local.addr;
|
||
|
|
result = SetWord(localInfo->NextResultTuple());
|
||
|
|
return result.addr != 0 ? YIELD : CANCEL;
|
||
|
|
case CLOSE:
|
||
|
|
ccHashMeasurer.PrintCPUTimeAndReset("CPU Time for Hashing Tuples : ");
|
||
|
|
ccBucketMeasurer.PrintCPUTimeAndReset(
|
||
|
|
"CPU Time for Computing Products of Buckets : ");
|
||
|
|
|
||
|
|
localInfo = (CcHashJoinLocalInfo*)local.addr;
|
||
|
|
if(localInfo)
|
||
|
|
{
|
||
|
|
delete localInfo;
|
||
|
|
local = SetWord(Address(0));
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Specification of Operator ~hashjoin~
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string CcHashJoinSpec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" "
|
||
|
|
"\"Meaning\" \"Example\" ) "
|
||
|
|
"( <text>((stream (mtuple ((x1 t1) ... "
|
||
|
|
"(xn tn)))) (stream (mtuple ((y1 d1) ... "
|
||
|
|
"(ym dm)))) xi yj nbuckets) -> (stream "
|
||
|
|
"(mtuple ((x1 t1) ... (xn tn) (y1 d1) ..."
|
||
|
|
" (ym dm))))</text--->"
|
||
|
|
"<text> _ _ hashjoin [ _ , _ , _ ]"
|
||
|
|
"</text--->"
|
||
|
|
"<text>Computes the equijoin two streams "
|
||
|
|
"via a hash join. The number of hash buckets"
|
||
|
|
" is given by the parameter nBuckets."
|
||
|
|
"</text--->"
|
||
|
|
"<text>query Employee feed Dept feed "
|
||
|
|
"rename[A] hashjoin[DeptNr, DeptNr_A, 17] "
|
||
|
|
"sort consume</text--->"
|
||
|
|
") )";
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Definition of Operator ~hashjoin~
|
||
|
|
|
||
|
|
*/
|
||
|
|
Operator ccrelhashjoin (
|
||
|
|
"hashjoin", // name
|
||
|
|
CcHashJoinSpec, // specification
|
||
|
|
CcHashJoin, // value mapping
|
||
|
|
Operator::SimpleSelect, // trivial selection function
|
||
|
|
CcJoinTypeMap<true, 2> // type mapping
|
||
|
|
);
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
7.3 Operator ~extend~
|
||
|
|
|
||
|
|
Extends each input tuple by new attributes as specified in the parameter list.
|
||
|
|
|
||
|
|
7.3.1 Type mapping function of operator ~extend~
|
||
|
|
|
||
|
|
Type mapping for ~extend~ is
|
||
|
|
|
||
|
|
---- ((stream x) ((b1 (map x y1)) ... (bm (map x ym))))
|
||
|
|
|
||
|
|
-> (stream (mtuple ((a1 x1) ... (an xn) (b1 y1 ... bm ym))))
|
||
|
|
|
||
|
|
where x = (mtuple ((a1 x1) ... (an xn)))
|
||
|
|
----
|
||
|
|
|
||
|
|
*/
|
||
|
|
static ListExpr
|
||
|
|
CcExtendTypeMap( ListExpr args )
|
||
|
|
{
|
||
|
|
ListExpr first, second, rest, listn, errorInfo,
|
||
|
|
lastlistn, first2, second2, firstr, outlist;
|
||
|
|
bool loopok;
|
||
|
|
AlgebraManager* algMgr;
|
||
|
|
|
||
|
|
algMgr = SecondoSystem::GetAlgebraManager();
|
||
|
|
errorInfo = nl->OneElemList(nl->SymbolAtom("ERROR"));
|
||
|
|
if(nl->ListLength(args) == 2)
|
||
|
|
{
|
||
|
|
first = nl->First(args);
|
||
|
|
second = nl->Second(args);
|
||
|
|
if((nl->ListLength(first) == 2) &&
|
||
|
|
(CcTypeOfRelAlgSymbol(nl->First(first)) == mstream) &&
|
||
|
|
(!nl->IsAtom(second)) &&
|
||
|
|
(nl->ListLength(second) > 0))
|
||
|
|
{
|
||
|
|
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);
|
||
|
|
}
|
||
|
|
loopok = true;
|
||
|
|
rest = second;
|
||
|
|
while (!(nl->IsEmpty(rest)))
|
||
|
|
{
|
||
|
|
firstr = nl->First(rest);
|
||
|
|
rest = nl->Rest(rest);
|
||
|
|
first2 = nl->First(firstr);
|
||
|
|
second2 = nl->Second(firstr);
|
||
|
|
if ((nl->IsAtom(first2)) &&
|
||
|
|
(nl->ListLength(second2) == 3) &&
|
||
|
|
(nl->AtomType(first2) == SymbolType) &&
|
||
|
|
(CcTypeOfRelAlgSymbol(nl->First(second2)) == mmap) &&
|
||
|
|
(algMgr->CheckKind(Kind::DATA(), nl->Third(second2), errorInfo)) &&
|
||
|
|
(nl->Equal(nl->Second(first),nl->Second(second2))))
|
||
|
|
{
|
||
|
|
lastlistn = nl->Append(lastlistn,
|
||
|
|
(nl->TwoElemList(first2,nl->Third(second2))));
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
loopok = false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if ((loopok) && (CcCompareNames(listn)))
|
||
|
|
{
|
||
|
|
outlist =
|
||
|
|
nl->TwoElemList(
|
||
|
|
nl->SymbolAtom(Symbol::STREAM()),
|
||
|
|
nl->TwoElemList(nl->SymbolAtom(CcTuple::BasicType()),listn));
|
||
|
|
return outlist;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
ErrorReporter::ReportError("Incorrect input for operator extend.");
|
||
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
ErrorReporter::ReportError("Incorrect input for operator extend.");
|
||
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
ErrorReporter::ReportError("Incorrect input for operator extend.");
|
||
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
||
|
|
}
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.2 Value mapping function of operator ~extend~
|
||
|
|
|
||
|
|
*/
|
||
|
|
static int
|
||
|
|
CcExtend(Word* args, Word& result, int message, Word& local, Supplier s)
|
||
|
|
{
|
||
|
|
Word t, value;
|
||
|
|
CcTuple* tup;
|
||
|
|
Supplier supplier, supplier2, supplier3;
|
||
|
|
int noofoldattrs, nooffun, noofsons;
|
||
|
|
ArgVectorPointer funargs;
|
||
|
|
|
||
|
|
switch (message)
|
||
|
|
{
|
||
|
|
case OPEN :
|
||
|
|
|
||
|
|
qp->Open(args[0].addr);
|
||
|
|
return 0;
|
||
|
|
|
||
|
|
case REQUEST :
|
||
|
|
|
||
|
|
qp->Request(args[0].addr,t);
|
||
|
|
if (qp->Received(args[0].addr))
|
||
|
|
{
|
||
|
|
tup = (CcTuple*)t.addr;
|
||
|
|
tup = tup->CloneIfNecessary();
|
||
|
|
noofoldattrs = tup->GetNoAttrs();
|
||
|
|
supplier = args[1].addr;
|
||
|
|
nooffun = qp->GetNoSons(supplier);
|
||
|
|
for (int i=0; i < nooffun;i++)
|
||
|
|
{
|
||
|
|
supplier2 = qp->GetSupplier(supplier, i);
|
||
|
|
noofsons = qp->GetNoSons(supplier2);
|
||
|
|
supplier3 = qp->GetSupplier(supplier2, 1);
|
||
|
|
funargs = qp->Argument(supplier3);
|
||
|
|
(*funargs)[0] = SetWord(tup);
|
||
|
|
qp->Request(supplier3,value);
|
||
|
|
tup->Put(noofoldattrs+i,((Attribute*)value.addr)->Clone());
|
||
|
|
}
|
||
|
|
|
||
|
|
tup->SetNoAttrs(noofoldattrs + nooffun);
|
||
|
|
result = SetWord(tup);
|
||
|
|
return YIELD;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
return CANCEL;
|
||
|
|
|
||
|
|
case CLOSE :
|
||
|
|
|
||
|
|
qp->Close(args[0].addr);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Specification of operator ~extend~
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string CcExtendSpec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
||
|
|
"\"Example\" ) "
|
||
|
|
"( <text>(stream(mtuple(x)) x [(a1, (mtuple(x)"
|
||
|
|
" -> d1)) ... (an, (mtuple(x) -> dn))] -> "
|
||
|
|
"stream(mtuple(x@[a1:d1, ... , an:dn])))"
|
||
|
|
"</text--->"
|
||
|
|
"<text>_ extend [funlist]</text--->"
|
||
|
|
"<text>Extends each input tuple by new "
|
||
|
|
"attributes as specified in the parameter"
|
||
|
|
" list.</text--->"
|
||
|
|
"<text>query ten feed extend [mult5 : "
|
||
|
|
".nr * 5, mod2 : .nr mod 2] consume"
|
||
|
|
"</text--->"
|
||
|
|
") )";
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Definition of operator ~extend~
|
||
|
|
|
||
|
|
*/
|
||
|
|
Operator ccrelextend (
|
||
|
|
"extend", // name
|
||
|
|
CcExtendSpec, // specification
|
||
|
|
CcExtend, // value mapping
|
||
|
|
Operator::SimpleSelect, // trivial selection function
|
||
|
|
CcExtendTypeMap // type mapping
|
||
|
|
);
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
7.3 Operator ~loopjoin~
|
||
|
|
|
||
|
|
This operator will fulfill a join of two relations. Tuples in the cartesian product which satisfy certain
|
||
|
|
conditions are passed on to the output stream.
|
||
|
|
|
||
|
|
For instance,
|
||
|
|
|
||
|
|
---- query Staedte feed loopjoin [plz feed filter [.Ort=.SName] ] consume;
|
||
|
|
|
||
|
|
(query (consume (loopjoin (feed tryrel) (fun (t1 TUPLE) (filter (feed null)
|
||
|
|
(fun t2 TUPLE) (= (attr t1 name) (attr t2 pname)))))))
|
||
|
|
----
|
||
|
|
|
||
|
|
7.3.1 Type mapping function of operator ~loopjoin~
|
||
|
|
|
||
|
|
The type mapping function of the loopjoin operation is as follows:
|
||
|
|
|
||
|
|
---- ((stream (mtuple x)) (map (mtuple x) (stream (mtuple y)))) -> (stream (mtuple x * y))
|
||
|
|
where x = ((x1 t1) ... (xn tn)) and y = ((y1 d1) ... (ym dm))
|
||
|
|
----
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr
|
||
|
|
CcLoopjoinTypeMap(ListExpr args)
|
||
|
|
{
|
||
|
|
ListExpr first, second;
|
||
|
|
ListExpr list1, list2, list, outlist;
|
||
|
|
|
||
|
|
if(nl->ListLength(args) == 2)
|
||
|
|
{
|
||
|
|
first = nl->First(args);
|
||
|
|
second = nl->Second(args);
|
||
|
|
|
||
|
|
if( (nl->ListLength(first) == 2)
|
||
|
|
&& (CcTypeOfRelAlgSymbol(nl->First(first)) == mstream)
|
||
|
|
&& (nl->ListLength(nl->Second(first)) == 2)
|
||
|
|
&& (CcTypeOfRelAlgSymbol(nl->First(nl->Second(first))) == mtuple)
|
||
|
|
&& (nl->ListLength(second) == 3)
|
||
|
|
&& (CcTypeOfRelAlgSymbol(nl->First(second)) == mmap)
|
||
|
|
&& (nl->Equal(nl->Second(first), nl->Second(second)))
|
||
|
|
&& (nl->ListLength(nl->Third(second)) == 2)
|
||
|
|
&& (CcTypeOfRelAlgSymbol(nl->First(nl->Third(second))) == mstream)
|
||
|
|
&& (nl->ListLength(nl->Second(nl->Third(second))) == 2)
|
||
|
|
&& (CcTypeOfRelAlgSymbol(nl->First(nl->Second(nl->Third(second))))
|
||
|
|
== mtuple) )
|
||
|
|
{
|
||
|
|
list1 = nl->Second(nl->Second(first));
|
||
|
|
list2 = nl->Second(nl->Second(nl->Third(second)));
|
||
|
|
if(!CcAttributesAreDisjoint(list1, list2))
|
||
|
|
{
|
||
|
|
goto typeerror;
|
||
|
|
}
|
||
|
|
list = CcConcatLists(list1, list2);
|
||
|
|
outlist = nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()),
|
||
|
|
nl->TwoElemList(nl->SymbolAtom(CcTuple::BasicType()), list));
|
||
|
|
return outlist;
|
||
|
|
}
|
||
|
|
else goto typeerror;
|
||
|
|
}
|
||
|
|
else goto typeerror;
|
||
|
|
|
||
|
|
typeerror:
|
||
|
|
ErrorReporter::ReportError("Incorrect input for operator loopjoin.");
|
||
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.2 Value mapping function of operator ~loopjoin~
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
struct CcLoopjoinLocalInfo
|
||
|
|
{
|
||
|
|
Word tuplex;
|
||
|
|
Word streamy;
|
||
|
|
};
|
||
|
|
|
||
|
|
static int
|
||
|
|
CcLoopjoin(Word* args, Word& result, int message, Word& local, Supplier s)
|
||
|
|
{
|
||
|
|
ArgVectorPointer funargs;
|
||
|
|
Word tuplex, tupley, tuplexy, streamy;
|
||
|
|
CcTuple* ctuplex;
|
||
|
|
CcTuple* ctupley;
|
||
|
|
CcTuple* ctuplexy;
|
||
|
|
CcLoopjoinLocalInfo *localinfo;
|
||
|
|
|
||
|
|
switch ( message )
|
||
|
|
{
|
||
|
|
case OPEN:
|
||
|
|
//1.open the stream and initiate the variables
|
||
|
|
qp->Open (args[0].addr);
|
||
|
|
qp->Request(args[0].addr, tuplex);
|
||
|
|
if (qp->Received(args[0].addr))
|
||
|
|
{
|
||
|
|
//2>>> here: compute the rely which corresponding to tuplex
|
||
|
|
funargs = qp->Argument(args[1].addr);
|
||
|
|
(*funargs)[0] = tuplex;
|
||
|
|
streamy=args[1];
|
||
|
|
qp->Open (streamy.addr);
|
||
|
|
//3>>> here: put the information of tuplex and rely into local
|
||
|
|
localinfo=new CcLoopjoinLocalInfo;
|
||
|
|
localinfo->tuplex=tuplex;
|
||
|
|
localinfo->streamy=streamy;
|
||
|
|
local = SetWord(localinfo);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
local = SetWord(Address(0));
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
|
||
|
|
case REQUEST:
|
||
|
|
if (local.addr ==0) return CANCEL;
|
||
|
|
//1>>>>>>restore localinformation from the local variable.
|
||
|
|
localinfo=(CcLoopjoinLocalInfo *) local.addr;
|
||
|
|
tuplex=localinfo->tuplex;
|
||
|
|
ctuplex=(CcTuple*)tuplex.addr;
|
||
|
|
streamy=localinfo->streamy;
|
||
|
|
//2>>>>>> prepare tuplex and tupley for processing.
|
||
|
|
//if rely is exausted: fetch next tuplex.
|
||
|
|
tupley=SetWord(Address(0));
|
||
|
|
while (tupley.addr==0)
|
||
|
|
{
|
||
|
|
qp->Request(streamy.addr, tupley);
|
||
|
|
if (!(qp->Received(streamy.addr)))
|
||
|
|
{
|
||
|
|
qp->Close(streamy.addr);
|
||
|
|
((CcTuple*)tuplex.addr)->DeleteIfAllowed();
|
||
|
|
qp->Request(args[0].addr, tuplex);
|
||
|
|
if (qp->Received(args[0].addr))
|
||
|
|
{
|
||
|
|
funargs = qp->Argument(args[1].addr);
|
||
|
|
ctuplex=(CcTuple*)tuplex.addr;
|
||
|
|
(*funargs)[0] = tuplex;
|
||
|
|
streamy=args[1];
|
||
|
|
qp->Open (streamy.addr);
|
||
|
|
tupley=SetWord(Address(0));
|
||
|
|
|
||
|
|
localinfo->tuplex=tuplex;
|
||
|
|
localinfo->streamy=streamy;
|
||
|
|
local = SetWord(localinfo);
|
||
|
|
}
|
||
|
|
else return CANCEL;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
ctupley=(CcTuple*)tupley.addr;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
//3>>>>>> compute tuplexy.
|
||
|
|
ctuplexy = new CcTuple();
|
||
|
|
ctuplexy->SetFree(true);
|
||
|
|
tuplexy = SetWord(ctuplexy);
|
||
|
|
CcConcat(tuplex, tupley, tuplexy);
|
||
|
|
((CcTuple*)tupley.addr)->DeleteIfAllowed();
|
||
|
|
result = tuplexy;
|
||
|
|
return YIELD;
|
||
|
|
|
||
|
|
case CLOSE:
|
||
|
|
qp->Close(args[0].addr);
|
||
|
|
localinfo=(CcLoopjoinLocalInfo *) local.addr;
|
||
|
|
if(localinfo)
|
||
|
|
{
|
||
|
|
delete localinfo;
|
||
|
|
local = SetWord(Address(0));
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Specification of operator ~loopjoin~
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string CcLoopjoinSpec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
||
|
|
"\"Example\" ) "
|
||
|
|
"( <text>((stream mtuple1) (map mtuple1 "
|
||
|
|
"mrel(mtuple2))) -> (stream mtuple1*mtuple2)"
|
||
|
|
"</text--->"
|
||
|
|
"<text>_ loopjoin [ fun ]</text--->"
|
||
|
|
"<text>Only tuples in the cartesian product "
|
||
|
|
"which satisfy certain conditions are passed on"
|
||
|
|
" to the output stream.</text--->"
|
||
|
|
"<text>query cities feed loopjoin [five feed "
|
||
|
|
"filter [.no > 2]] consume</text--->"
|
||
|
|
") )";
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Definition of operator ~loopjoin~
|
||
|
|
|
||
|
|
*/
|
||
|
|
Operator ccrelloopjoin (
|
||
|
|
"loopjoin", // name
|
||
|
|
CcLoopjoinSpec, // specification
|
||
|
|
CcLoopjoin, // value mapping
|
||
|
|
Operator::SimpleSelect, // trivial selection function
|
||
|
|
CcLoopjoinTypeMap // type mapping
|
||
|
|
);
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
7.4 Operator ~loopselect~
|
||
|
|
|
||
|
|
This operator is similar to the ~loopjoin~ operator except that it only returns the inner tuple
|
||
|
|
(instead of the concatination of two tuples). Tuples in the cartesian product which satisfy
|
||
|
|
certain conditions are passed on to the output stream.
|
||
|
|
|
||
|
|
For instance,
|
||
|
|
|
||
|
|
---- query Staedte feed loopselect [plz feed filter [.Ort=.SName] ] consume;
|
||
|
|
|
||
|
|
(query (consume (loopselect (feed tryrel) (fun (t1 TUPLE) (filter (feed null)
|
||
|
|
(fun t2 TUPLE) (= (attr t1 name) (attr t2 pname)))))))
|
||
|
|
----
|
||
|
|
|
||
|
|
7.4.1 Type mapping function of operator ~loopselect~
|
||
|
|
|
||
|
|
The type mapping function of the loopjoin operation is as follows:
|
||
|
|
|
||
|
|
---- ((stream (mtuple x)) (map (mtuple x) (stream (mtuple y)))) -> (stream (mtuple y))
|
||
|
|
where x = ((x1 t1) ... (xn tn)) and y = ((y1 d1) ... (ym dm))
|
||
|
|
----
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr
|
||
|
|
CcLoopselectTypeMap(ListExpr args)
|
||
|
|
{
|
||
|
|
ListExpr first, second;
|
||
|
|
ListExpr list1, list2, outlist;
|
||
|
|
|
||
|
|
if(nl->ListLength(args) == 2)
|
||
|
|
{
|
||
|
|
first = nl->First(args);
|
||
|
|
second = nl->Second(args);
|
||
|
|
|
||
|
|
if( (nl->ListLength(first) == 2)
|
||
|
|
&& (CcTypeOfRelAlgSymbol(nl->First(first)) == mstream)
|
||
|
|
&& (nl->ListLength(nl->Second(first)) == 2)
|
||
|
|
&& (CcTypeOfRelAlgSymbol(nl->First(nl->Second(first))) == mtuple)
|
||
|
|
&& (nl->ListLength(second) == 3)
|
||
|
|
&& (CcTypeOfRelAlgSymbol(nl->First(second)) == mmap)
|
||
|
|
&& (nl->Equal(nl->Second(first), nl->Second(second)))
|
||
|
|
&& (nl->ListLength(nl->Third(second)) == 2)
|
||
|
|
&& (CcTypeOfRelAlgSymbol(nl->First(nl->Third(second))) == mstream)
|
||
|
|
&& (nl->ListLength(nl->Second(nl->Third(second))) == 2)
|
||
|
|
&& (CcTypeOfRelAlgSymbol(nl->First(nl->Second(nl->Third(second))))
|
||
|
|
== mtuple) )
|
||
|
|
{
|
||
|
|
list1 = nl->Second(nl->Second(first));
|
||
|
|
list2 = nl->Second(nl->Second(nl->Third(second)));
|
||
|
|
//if(!CcAttributesAreDisjoint(list1, list2))
|
||
|
|
//{
|
||
|
|
// goto typeerror;
|
||
|
|
//}
|
||
|
|
//list = CcConcatLists(list1, list2);
|
||
|
|
outlist = nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()),
|
||
|
|
nl->TwoElemList(nl->SymbolAtom(CcTuple::BasicType()), list2));
|
||
|
|
return outlist;
|
||
|
|
}
|
||
|
|
else goto typeerror;
|
||
|
|
}
|
||
|
|
else goto typeerror;
|
||
|
|
|
||
|
|
typeerror:
|
||
|
|
ErrorReporter::ReportError("Incorrect input for operator loopselect.");
|
||
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.2 Value mapping function of operator ~loopjoin~
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
struct CcLoopselectLocalInfo
|
||
|
|
{
|
||
|
|
Word tuplex;
|
||
|
|
Word streamy;
|
||
|
|
};
|
||
|
|
|
||
|
|
static int
|
||
|
|
CcLoopselect(Word* args, Word& result, int message, Word& local, Supplier s)
|
||
|
|
{
|
||
|
|
ArgVectorPointer funargs;
|
||
|
|
Word tuplex, tupley, streamy; //tuplexy
|
||
|
|
CcTuple* ctuplex;
|
||
|
|
CcTuple* ctupley;
|
||
|
|
//CcTuple* ctuplexy;
|
||
|
|
CcLoopselectLocalInfo *localinfo;
|
||
|
|
|
||
|
|
switch ( message )
|
||
|
|
{
|
||
|
|
case OPEN:
|
||
|
|
//1.open the stream and initiate the variables
|
||
|
|
qp->Open (args[0].addr);
|
||
|
|
qp->Request(args[0].addr, tuplex);
|
||
|
|
if (qp->Received(args[0].addr))
|
||
|
|
{
|
||
|
|
//2>>> here: compute the rely which corresponding to tuplex
|
||
|
|
funargs = qp->Argument(args[1].addr);
|
||
|
|
(*funargs)[0] = tuplex;
|
||
|
|
streamy=args[1];
|
||
|
|
qp->Open (streamy.addr);
|
||
|
|
//3>>> here: put the information of tuplex and rely into local
|
||
|
|
localinfo=new CcLoopselectLocalInfo;
|
||
|
|
localinfo->tuplex=tuplex;
|
||
|
|
localinfo->streamy=streamy;
|
||
|
|
local = SetWord(localinfo);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
local = SetWord(Address(0));
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
|
||
|
|
case REQUEST:
|
||
|
|
if (local.addr ==0) return CANCEL;
|
||
|
|
//1>>>>>>restore localinformation from the local variable.
|
||
|
|
localinfo=(CcLoopselectLocalInfo *) local.addr;
|
||
|
|
tuplex=localinfo->tuplex;
|
||
|
|
ctuplex=(CcTuple*)tuplex.addr;
|
||
|
|
streamy=localinfo->streamy;
|
||
|
|
//2>>>>>> prepare tuplex and tupley for processing.
|
||
|
|
//if rely is exausted: fetch next tuplex.
|
||
|
|
tupley=SetWord(Address(0));
|
||
|
|
while (tupley.addr==0)
|
||
|
|
{
|
||
|
|
qp->Request(streamy.addr, tupley);
|
||
|
|
if (!(qp->Received(streamy.addr)))
|
||
|
|
{
|
||
|
|
qp->Close(streamy.addr);
|
||
|
|
((CcTuple*)tuplex.addr)->DeleteIfAllowed();
|
||
|
|
qp->Request(args[0].addr, tuplex);
|
||
|
|
if (qp->Received(args[0].addr))
|
||
|
|
{
|
||
|
|
funargs = qp->Argument(args[1].addr);
|
||
|
|
ctuplex=(CcTuple*)tuplex.addr;
|
||
|
|
(*funargs)[0] = tuplex;
|
||
|
|
streamy=args[1];
|
||
|
|
qp->Open (streamy.addr);
|
||
|
|
tupley=SetWord(Address(0));
|
||
|
|
|
||
|
|
localinfo->tuplex=tuplex;
|
||
|
|
localinfo->streamy=streamy;
|
||
|
|
local = SetWord(localinfo);
|
||
|
|
}
|
||
|
|
else return CANCEL;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
ctupley=(CcTuple*)tupley.addr;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
//3>>>>>> compute tuplexy.
|
||
|
|
//ctuplexy = new CcTuple();
|
||
|
|
//ctuplexy->SetFree(true);
|
||
|
|
//tuplexy = SetWord(ctuplexy);
|
||
|
|
//CcConcat(tuplex, tupley, tuplexy);
|
||
|
|
//((CcTuple*)tupley.addr)->DeleteIfAllowed();
|
||
|
|
result = tupley;
|
||
|
|
return YIELD;
|
||
|
|
|
||
|
|
case CLOSE:
|
||
|
|
qp->Close(args[0].addr);
|
||
|
|
localinfo=(CcLoopselectLocalInfo *) local.addr;
|
||
|
|
if(localinfo)
|
||
|
|
{
|
||
|
|
delete localinfo;
|
||
|
|
local = SetWord(Address(0));
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Specification of operator ~loopjoin~
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string CcLoopselectSpec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
||
|
|
"\"Example\" ) "
|
||
|
|
"( <text>((stream mtuple1) (map mtuple1 "
|
||
|
|
"mrel(mtuple2))) -> (stream mtuple2)"
|
||
|
|
"</text--->"
|
||
|
|
"<text>_ loopselect [ fun ]</text--->"
|
||
|
|
"<text>Only tuples in the cartesian product "
|
||
|
|
"which satisfy certain conditions are passed on"
|
||
|
|
" to the output stream.</text--->"
|
||
|
|
"<text>query cities feed loopselect [five feed "
|
||
|
|
"filter [.no > 2]] consume</text--->"
|
||
|
|
") )";
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Definition of operator ~loopjoin~
|
||
|
|
|
||
|
|
*/
|
||
|
|
Operator ccrelloopselect (
|
||
|
|
"loopsel", // name
|
||
|
|
CcLoopselectSpec, // specification
|
||
|
|
CcLoopselect, // value mapping
|
||
|
|
Operator::SimpleSelect, // trivial selection function
|
||
|
|
CcLoopselectTypeMap // type mapping
|
||
|
|
);
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
7.3 Operator ~loopjoinrel~
|
||
|
|
|
||
|
|
This operator will fulfill a join of two relations. Tuples in the cartesian product which satisfy certain
|
||
|
|
conditions are passed on to the output stream.
|
||
|
|
|
||
|
|
For instance,
|
||
|
|
|
||
|
|
---- query Staedte feed loopjoinrel [plz feed filter [.Ort=.SName] consume] consume;
|
||
|
|
|
||
|
|
(query (consume (loopjoinrel (feed tryrel) (fun (t1 TUPLE)
|
||
|
|
(consume filter (feed null) (fun t2 TUPLE) (= (attr t1 name) (attr t2 pname)))))))
|
||
|
|
----
|
||
|
|
|
||
|
|
7.3.1 Type mapping function of operator ~loopjoinrel~
|
||
|
|
|
||
|
|
The type mapping function of the loopjoinrel operation is as follows:
|
||
|
|
|
||
|
|
---- ((stream (mtuple x)) (map (mtuple x) (mrel (mtuple y)))) -> (stream (mtuple x * y))
|
||
|
|
where x = ((x1 t1) ... (xn tn)) and y = ((y1 d1) ... (ym dm))
|
||
|
|
----
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr
|
||
|
|
CcLoopjoinrelTypeMap(ListExpr args)
|
||
|
|
{
|
||
|
|
ListExpr first, second;
|
||
|
|
ListExpr list1, list2, list, outlist;
|
||
|
|
|
||
|
|
if(nl->ListLength(args) == 2)
|
||
|
|
{
|
||
|
|
first = nl->First(args);
|
||
|
|
second = nl->Second(args);
|
||
|
|
|
||
|
|
if( (nl->ListLength(first) == 2)
|
||
|
|
&& (CcTypeOfRelAlgSymbol(nl->First(first)) == mstream)
|
||
|
|
&& (nl->ListLength(nl->Second(first)) == 2)
|
||
|
|
&& (CcTypeOfRelAlgSymbol(nl->First(nl->Second(first))) == mtuple)
|
||
|
|
&& (nl->ListLength(second) == 3)
|
||
|
|
&& (CcTypeOfRelAlgSymbol(nl->First(second)) == mmap)
|
||
|
|
&& (nl->Equal(nl->Second(first), nl->Second(second)))
|
||
|
|
&& (nl->ListLength(nl->Third(second)) == 2)
|
||
|
|
&& (CcTypeOfRelAlgSymbol(nl->First(nl->Third(second))) == mrel)
|
||
|
|
&& (nl->ListLength(nl->Second(nl->Third(second))) == 2)
|
||
|
|
&& (CcTypeOfRelAlgSymbol(nl->First(nl->Second(nl->Third(second))))
|
||
|
|
== mtuple) )
|
||
|
|
{
|
||
|
|
list1 = nl->Second(nl->Second(first));
|
||
|
|
list2 = nl->Second(nl->Second(nl->Third(second)));
|
||
|
|
if(!CcAttributesAreDisjoint(list1, list2))
|
||
|
|
{
|
||
|
|
goto typeerror;
|
||
|
|
}
|
||
|
|
list = CcConcatLists(list1, list2);
|
||
|
|
outlist = nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()),
|
||
|
|
nl->TwoElemList(nl->SymbolAtom(CcTuple::BasicType()), list));
|
||
|
|
return outlist;
|
||
|
|
}
|
||
|
|
else goto typeerror;
|
||
|
|
}
|
||
|
|
else goto typeerror;
|
||
|
|
|
||
|
|
typeerror:
|
||
|
|
ErrorReporter::ReportError("Incorrect input for operator loopjoinrel.");
|
||
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.2 Value mapping function of operator ~loopjoinrel~
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
struct CcLoopjoinrelLocalInfo
|
||
|
|
{
|
||
|
|
Word tuplex;
|
||
|
|
Word rely;
|
||
|
|
Word relyit;
|
||
|
|
};
|
||
|
|
|
||
|
|
static int
|
||
|
|
CcLoopjoinrel(Word* args, Word& result, int message, Word& local, Supplier s)
|
||
|
|
{
|
||
|
|
ArgVectorPointer funargs;
|
||
|
|
Word tuplex, tupley, tuplexy, funresult, rely;
|
||
|
|
CcTuple* ctuplex;
|
||
|
|
CcTuple* ctupley;
|
||
|
|
CcTuple* ctuplexy;
|
||
|
|
CcRel* crely;
|
||
|
|
CcRelIT* crelyit;
|
||
|
|
CcLoopjoinrelLocalInfo *localinfo;
|
||
|
|
|
||
|
|
switch ( message )
|
||
|
|
{
|
||
|
|
case OPEN:
|
||
|
|
//1.open the stream and initiate the variables
|
||
|
|
qp->Open (args[0].addr);
|
||
|
|
qp->Request(args[0].addr, tuplex);
|
||
|
|
if (qp->Received(args[0].addr))
|
||
|
|
{
|
||
|
|
//2>>> here: compute the rely which corresponding to tuplex
|
||
|
|
funargs = qp->Argument(args[1].addr);
|
||
|
|
ctuplex=(CcTuple*)tuplex.addr;
|
||
|
|
(*funargs)[0] = tuplex;
|
||
|
|
qp->Request(args[1].addr, funresult);
|
||
|
|
rely=funresult;
|
||
|
|
crely = (CcRel*)(funresult.addr);
|
||
|
|
crelyit=crely->MakeNewScan();
|
||
|
|
//3>>> here: put the information of tuplex and rely into local
|
||
|
|
localinfo=new CcLoopjoinrelLocalInfo;
|
||
|
|
localinfo->tuplex=tuplex;
|
||
|
|
localinfo->rely=rely;
|
||
|
|
localinfo->relyit=SetWord(crelyit);
|
||
|
|
local = SetWord(localinfo);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
local = SetWord(Address(0));
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
|
||
|
|
case REQUEST:
|
||
|
|
if (local.addr ==0) return CANCEL;
|
||
|
|
//1>>>>>>restore localinformation from the local variable.
|
||
|
|
localinfo=(CcLoopjoinrelLocalInfo *) local.addr;
|
||
|
|
tuplex=localinfo->tuplex;
|
||
|
|
ctuplex=(CcTuple*)tuplex.addr;
|
||
|
|
rely=localinfo->rely;
|
||
|
|
crely=((CcRel*)rely.addr);
|
||
|
|
crelyit=(CcRelIT*)((localinfo->relyit).addr);
|
||
|
|
//2>>>>>> prepare tuplex and tupley for processing.
|
||
|
|
//if rely is exausted: fetch next tuplex.
|
||
|
|
tupley=SetWord(Address(0));
|
||
|
|
while (tupley.addr==0)
|
||
|
|
{
|
||
|
|
crely=((CcRel*)rely.addr);
|
||
|
|
if (crelyit->EndOfScan())
|
||
|
|
{
|
||
|
|
((CcTuple*)tuplex.addr)->DeleteIfAllowed();
|
||
|
|
qp->Request(args[0].addr, tuplex);
|
||
|
|
if (qp->Received(args[0].addr))
|
||
|
|
{
|
||
|
|
funargs = qp->Argument(args[1].addr);
|
||
|
|
ctuplex=(CcTuple*)tuplex.addr;
|
||
|
|
(*funargs)[0] = tuplex;
|
||
|
|
qp->Request(args[1].addr, funresult);
|
||
|
|
rely=SetWord(funresult.addr);
|
||
|
|
crely = (CcRel*)(funresult.addr);
|
||
|
|
crelyit=crely->MakeNewScan();
|
||
|
|
tupley=SetWord(Address(0));
|
||
|
|
//cout<<"number of tuples in rel y:"
|
||
|
|
// <<((CcRel*)rely.addr)->GetNoTuples()<<endl;
|
||
|
|
|
||
|
|
localinfo->tuplex=tuplex;
|
||
|
|
localinfo->rely=rely;
|
||
|
|
localinfo->relyit=SetWord(crelyit);
|
||
|
|
local = SetWord(localinfo);
|
||
|
|
}
|
||
|
|
else return CANCEL;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
tupley=SetWord(crelyit->GetTuple());
|
||
|
|
ctupley=(CcTuple*)tupley.addr;
|
||
|
|
crelyit->Next();
|
||
|
|
localinfo->relyit=SetWord(crelyit);
|
||
|
|
local = SetWord(localinfo);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
//3>>>>>> compute tuplexy.
|
||
|
|
ctuplexy = new CcTuple();
|
||
|
|
ctuplexy->SetFree(true);
|
||
|
|
tuplexy = SetWord(ctuplexy);
|
||
|
|
CcConcat(tuplex, tupley, tuplexy);
|
||
|
|
((CcTuple*)tupley.addr)->DeleteIfAllowed();
|
||
|
|
result = tuplexy;
|
||
|
|
return YIELD;
|
||
|
|
|
||
|
|
case CLOSE:
|
||
|
|
qp->Close(args[0].addr);
|
||
|
|
localinfo=(CcLoopjoinrelLocalInfo *) local.addr;
|
||
|
|
if(localinfo)
|
||
|
|
{
|
||
|
|
delete localinfo;
|
||
|
|
local = SetWord(Address(0));
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Specification of operator ~loopjoinrel~
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string CcLoopjoinrelSpec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
||
|
|
"\"Example\" ) "
|
||
|
|
"( <text>((stream mtuple1) (map mtuple1 mrel(mtuple2))) "
|
||
|
|
"-> (stream mtuple1*mtuple2)</text--->"
|
||
|
|
"<text>_ loopjoin [ fun ]</text--->"
|
||
|
|
"<text>Only tuples in the cartesian product which "
|
||
|
|
"satisfy certain conditions are passed on to the "
|
||
|
|
"output stream.</text--->"
|
||
|
|
"<text>query cities feed loopjoin [ five ] consume"
|
||
|
|
"</text--->"
|
||
|
|
" ) )";
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Definition of operator ~loopjoinrel~
|
||
|
|
|
||
|
|
*/
|
||
|
|
Operator ccrelloopjoinrel (
|
||
|
|
"loopjoinrel", // name
|
||
|
|
CcLoopjoinrelSpec, // specification
|
||
|
|
CcLoopjoinrel, // value mapping
|
||
|
|
Operator::SimpleSelect, // trivial selection function
|
||
|
|
CcLoopjoinrelTypeMap // type mapping
|
||
|
|
);
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
7.3 Operator ~concat~
|
||
|
|
|
||
|
|
7.3.1 Type mapping function of operator ~concat~
|
||
|
|
|
||
|
|
Type mapping for ~concat~ is
|
||
|
|
|
||
|
|
---- ((stream (mtuple (a1:d1 ... an:dn))) (stream (mtuple (b1:d1 ... bn:dn))))
|
||
|
|
|
||
|
|
-> (stream (mtuple (a1:d1 ... an:dn)))
|
||
|
|
----
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr CcGetAttrTypeList (ListExpr l)
|
||
|
|
{
|
||
|
|
ListExpr olist = nl->TheEmptyList();
|
||
|
|
ListExpr lastolist = nl->TheEmptyList();
|
||
|
|
ListExpr attrlist = l;
|
||
|
|
|
||
|
|
while (!nl->IsEmpty(attrlist))
|
||
|
|
{
|
||
|
|
ListExpr first = nl->First(attrlist);
|
||
|
|
attrlist = nl->Rest(attrlist);
|
||
|
|
if (olist == nl->TheEmptyList())
|
||
|
|
{
|
||
|
|
olist = nl->Cons(nl->Second(first), nl->TheEmptyList());
|
||
|
|
lastolist = olist;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
lastolist = nl->Append(lastolist, nl->Second(first));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return olist;
|
||
|
|
}
|
||
|
|
|
||
|
|
static ListExpr
|
||
|
|
CcConcatTypeMap( ListExpr args )
|
||
|
|
{
|
||
|
|
ListExpr first, second;
|
||
|
|
if(nl->ListLength(args) == 2)
|
||
|
|
{
|
||
|
|
first = nl->First(args);
|
||
|
|
second = nl->Second(args);
|
||
|
|
|
||
|
|
if((nl->ListLength(first) == 2) &&
|
||
|
|
(CcTypeOfRelAlgSymbol(nl->First(first)) == mstream) &&
|
||
|
|
(nl->ListLength(nl->Second(first)) == 2) &&
|
||
|
|
(CcTypeOfRelAlgSymbol(nl->First(nl->Second(first))) == mtuple) &&
|
||
|
|
(nl->ListLength(second) == 2) &&
|
||
|
|
(CcTypeOfRelAlgSymbol(nl->First(second)) == mstream) &&
|
||
|
|
(nl->ListLength(nl->Second(second)) == 2) &&
|
||
|
|
(CcTypeOfRelAlgSymbol(nl->First(nl->Second(second))) == mtuple) &&
|
||
|
|
(nl->Equal(CcGetAttrTypeList(nl->Second(nl->Second(first))),
|
||
|
|
CcGetAttrTypeList(nl->Second(nl->Second(second))))))
|
||
|
|
return first;
|
||
|
|
else
|
||
|
|
{
|
||
|
|
ErrorReporter::ReportError("Incorrect input for operator concat.");
|
||
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
ErrorReporter::ReportError("Incorrect input for operator concat.");
|
||
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
||
|
|
}
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.2 Value mapping function of operator ~concat~
|
||
|
|
|
||
|
|
*/
|
||
|
|
static int
|
||
|
|
CcConcat(Word* args, Word& result, int message, Word& local, Supplier s)
|
||
|
|
{
|
||
|
|
Word t;
|
||
|
|
CcTuple* tuple;
|
||
|
|
|
||
|
|
switch (message)
|
||
|
|
{
|
||
|
|
case OPEN :
|
||
|
|
|
||
|
|
qp->Open(args[0].addr);
|
||
|
|
qp->Open(args[1].addr);
|
||
|
|
local = SetWord(new CcInt(true, 0));
|
||
|
|
return 0;
|
||
|
|
|
||
|
|
case REQUEST :
|
||
|
|
if ( (((CcInt*)local.addr)->GetIntval()) == 0)
|
||
|
|
{
|
||
|
|
qp->Request(args[0].addr, t);
|
||
|
|
if (qp->Received(args[0].addr))
|
||
|
|
{
|
||
|
|
tuple = (CcTuple*)t.addr;
|
||
|
|
result = SetWord(tuple);
|
||
|
|
return YIELD;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
((CcInt*)local.addr)->Set(1);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
qp->Request(args[1].addr, t);
|
||
|
|
if (qp->Received(args[1].addr))
|
||
|
|
{
|
||
|
|
tuple = (CcTuple*)t.addr;
|
||
|
|
result = SetWord(tuple);
|
||
|
|
return YIELD;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
return CANCEL;
|
||
|
|
|
||
|
|
case CLOSE :
|
||
|
|
|
||
|
|
qp->Close(args[0].addr);
|
||
|
|
qp->Close(args[1].addr);
|
||
|
|
if(local.addr)
|
||
|
|
{
|
||
|
|
delete (CcInt*)local.addr;
|
||
|
|
local = SetWord(Address(0));
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Specification of operator ~concat~
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string CcConcatSpec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
||
|
|
"\"Example\" ) "
|
||
|
|
"( <text>((stream (mtuple (a1:d1 ... an:dn))) "
|
||
|
|
"(stream (mtuple (b1:d1 ... bn:dn)))) -> (stream"
|
||
|
|
" (mtuple (a1:d1 ... an:dn)))</text--->"
|
||
|
|
"<text>_ _ concat</text--->"
|
||
|
|
"<text>Union.</text--->"
|
||
|
|
"<text>query ten feed five feed concat consume"
|
||
|
|
"</text--->"
|
||
|
|
") )";
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Definition of operator ~concat~
|
||
|
|
|
||
|
|
*/
|
||
|
|
Operator ccrelconcat (
|
||
|
|
"concat", // name
|
||
|
|
CcConcatSpec, // specification
|
||
|
|
CcConcat, // value mapping
|
||
|
|
Operator::SimpleSelect, // trivial selection function
|
||
|
|
CcConcatTypeMap // type mapping
|
||
|
|
);
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
7.20 Operator ~groupby~
|
||
|
|
|
||
|
|
|
||
|
|
7.20.1 Type mapping function of operator ~groupby~
|
||
|
|
|
||
|
|
Result type of ~groupby~ operation.
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr
|
||
|
|
CcGroupByTypeMap(ListExpr args)
|
||
|
|
{
|
||
|
|
// To avoid redundant code the type mapping is
|
||
|
|
// implemented in the file ExtRelationAlgebra.cpp
|
||
|
|
return GroupByTypeMap2(args, true);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
7.20.2 Value mapping function of operator ~groupby~
|
||
|
|
|
||
|
|
Remark this implementation causes a SIGSEGV - to be fixed!
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
int
|
||
|
|
CcGroupByValueMapping(Word* args, Word& result, int message,
|
||
|
|
Word& local, Supplier supplier)
|
||
|
|
{
|
||
|
|
CcTuple *t = 0;
|
||
|
|
CcTuple *s = 0;
|
||
|
|
Word sWord = SetWord(Address(0));
|
||
|
|
Word relWord = SetWord(Address(0));
|
||
|
|
CcRel* tp = 0;
|
||
|
|
CcRelIT* relIter = 0;
|
||
|
|
int i=0, j=0, k=0;
|
||
|
|
int numberatt = 0;
|
||
|
|
bool ifequal = false;
|
||
|
|
Word value = SetWord(Address(0));
|
||
|
|
Supplier value2;
|
||
|
|
Supplier supplier1;
|
||
|
|
Supplier supplier2;
|
||
|
|
int ind = 0;
|
||
|
|
int noOffun = 0;
|
||
|
|
ArgVectorPointer vector;
|
||
|
|
const int indexOfCountArgument = 3;
|
||
|
|
const int startIndexOfExtraArguments = indexOfCountArgument +1;
|
||
|
|
int attribIdx = 0;
|
||
|
|
Word nAttributesWord = SetWord(Address(0));
|
||
|
|
Word attribIdxWord = SetWord(Address(0));
|
||
|
|
|
||
|
|
switch(message)
|
||
|
|
{
|
||
|
|
case OPEN:
|
||
|
|
qp->Open (args[0].addr);
|
||
|
|
qp->Request(args[0].addr, sWord);
|
||
|
|
if (qp->Received(args[0].addr))
|
||
|
|
{
|
||
|
|
local = SetWord((CcTuple*)sWord.addr);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
local = SetWord(Address(0));
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
|
||
|
|
case REQUEST:
|
||
|
|
tp = new CcRel;
|
||
|
|
SHOW(tp)
|
||
|
|
if(local.addr == 0)
|
||
|
|
{
|
||
|
|
delete tp;
|
||
|
|
return CANCEL;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
t = (CcTuple*)local.addr;
|
||
|
|
t = t->Clone();
|
||
|
|
t->SetFree(false);
|
||
|
|
SHOW(t)
|
||
|
|
SHOW(*t)
|
||
|
|
tp->AppendTuple(t);
|
||
|
|
}
|
||
|
|
numberatt = ((CcInt*)args[indexOfCountArgument].addr)->GetIntval();
|
||
|
|
|
||
|
|
ifequal = true;
|
||
|
|
qp->Request(args[0].addr, sWord);
|
||
|
|
while ((qp->Received(args[0].addr)) && ifequal)
|
||
|
|
{
|
||
|
|
s = (CcTuple*)sWord.addr;
|
||
|
|
for (k = 0; k < numberatt; k++)
|
||
|
|
{
|
||
|
|
attribIdx =
|
||
|
|
((CcInt*)args[startIndexOfExtraArguments+k].addr)->GetIntval();
|
||
|
|
j = attribIdx - 1;
|
||
|
|
if (((Attribute*)t->Get(j))->Compare((Attribute *)s->Get(j)))
|
||
|
|
ifequal = false;
|
||
|
|
}
|
||
|
|
if (ifequal)
|
||
|
|
{
|
||
|
|
s = s->Clone();
|
||
|
|
s->SetFree(false);
|
||
|
|
SHOW(s)
|
||
|
|
SHOW(*s)
|
||
|
|
tp->AppendTuple(s);
|
||
|
|
qp->Request(args[0].addr, sWord);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
local = SetWord((CcTuple*)sWord.addr);
|
||
|
|
}
|
||
|
|
if(ifequal)
|
||
|
|
{
|
||
|
|
local = SetWord(Address(0));
|
||
|
|
}
|
||
|
|
|
||
|
|
t = new CcTuple;
|
||
|
|
t->SetFree(true);
|
||
|
|
SHOW(tp)
|
||
|
|
relIter = tp->MakeNewScan();
|
||
|
|
TRACE("GetNextTuple")
|
||
|
|
s = relIter->GetNextTuple();
|
||
|
|
|
||
|
|
SHOW(s)
|
||
|
|
SHOW(*s)
|
||
|
|
for(i = 0; i < numberatt; i++)
|
||
|
|
{
|
||
|
|
attribIdx =
|
||
|
|
((CcInt*)args[startIndexOfExtraArguments+i].addr)->GetIntval();
|
||
|
|
t->Put(i, ((Attribute*)s->Get(attribIdx - 1))->Clone());
|
||
|
|
}
|
||
|
|
value2 = (Supplier)args[2].addr;
|
||
|
|
noOffun = qp->GetNoSons(value2);
|
||
|
|
t->SetNoAttrs(numberatt + noOffun);
|
||
|
|
delete relIter;
|
||
|
|
|
||
|
|
SHOW(noOffun)
|
||
|
|
for(ind = 0; ind < noOffun; ind++)
|
||
|
|
{
|
||
|
|
supplier1 = qp->GetSupplier(value2, ind);
|
||
|
|
supplier2 = qp->GetSupplier(supplier1, 1);
|
||
|
|
vector = qp->Argument(supplier2);
|
||
|
|
(*vector)[0] = SetWord(tp);
|
||
|
|
qp->Request(supplier2, value);
|
||
|
|
t->Put(numberatt + ind, ((Attribute*)value.addr)->Clone()) ;
|
||
|
|
}
|
||
|
|
SHOW(*t)
|
||
|
|
result = SetWord(t);
|
||
|
|
relWord = SetWord(tp);
|
||
|
|
//DeleteCcRel(relWord);
|
||
|
|
return YIELD;
|
||
|
|
|
||
|
|
case CLOSE:
|
||
|
|
qp->Close(args[0].addr);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Specification of operator ~groupby~
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string CcGroupBySpec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
||
|
|
"\"Example\" ) "
|
||
|
|
"( <text>((stream (mtuple (a1:d1 ... an:dn))) "
|
||
|
|
"(ai1 ... aik) ((bj1 (fun (mrel (mtuple (a1:d1"
|
||
|
|
" ... an:dn))) (_))) ... (bjl (fun (mrel (mtuple"
|
||
|
|
" (a1:d1 ... an:dn))) (_))))) -> (stream (mtuple"
|
||
|
|
" (ai1:di1 ... aik:dik bj1 ... bjl)))</text--->"
|
||
|
|
"<text>_ groupby [list; funlist]</text--->"
|
||
|
|
"<text>Groups a relation according to attributes "
|
||
|
|
"ai1, ..., aik and feeds the groups to other "
|
||
|
|
"functions. The results of those functions are "
|
||
|
|
"appended to the grouping attributes.</text--->"
|
||
|
|
"<text>query Employee feed sortby[DeptNr asc] "
|
||
|
|
"groupby[DeptNr; anz : group feed count] consume"
|
||
|
|
"</text--->"
|
||
|
|
") )";
|
||
|
|
/*
|
||
|
|
|
||
|
|
4.1.3 Definition of operator ~groupby~
|
||
|
|
|
||
|
|
*/
|
||
|
|
Operator ccrelgroupby (
|
||
|
|
"groupby", // name
|
||
|
|
CcGroupBySpec, // specification
|
||
|
|
CcGroupByValueMapping, // value mapping
|
||
|
|
Operator::SimpleSelect, // trivial selection function
|
||
|
|
CcGroupByTypeMap // type mapping
|
||
|
|
);
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
5 Defnition of type constructor ~mtuple~
|
||
|
|
|
||
|
|
Eventually a type constructor is created by defining an instance of
|
||
|
|
class ~TypeConstructor~. Constructor's arguments are the type constructor's
|
||
|
|
name and the eleven functions previously defined.
|
||
|
|
|
||
|
|
*/
|
||
|
|
void DummyDelete(const ListExpr, Word& w) {};
|
||
|
|
void DummyClose(const ListExpr, Word& w) {};
|
||
|
|
Word DummyClone(const ListExpr, const Word& w)
|
||
|
|
{ return SetWord( Address(0) ); };
|
||
|
|
int DummySizeOf() { return 0; }
|
||
|
|
|
||
|
|
TypeConstructor ccreltuple( CcTuple::BasicType(), CcTupleProp,
|
||
|
|
OutCcTuple, InCcTuple,
|
||
|
|
SaveToListCcTuple, RestoreFromListCcTuple,
|
||
|
|
CreateCcTuple, DummyDelete,
|
||
|
|
0, 0,
|
||
|
|
DummyClose, DummyClone,
|
||
|
|
CastCcTuple, DummySizeOf,
|
||
|
|
CheckCcTuple );
|
||
|
|
/*
|
||
|
|
|
||
|
|
5 Definition of type constructor ~mrel~
|
||
|
|
|
||
|
|
Eventually a type constructor is created by defining an instance of
|
||
|
|
class ~TypeConstructor~. Constructor's arguments are the type constructor's
|
||
|
|
name and the eleven functions previously defined.
|
||
|
|
|
||
|
|
*/
|
||
|
|
TypeConstructor ccrelrel( CcRel::BasicType(), CcRelProp,
|
||
|
|
OutCcRel, InCcRel,
|
||
|
|
0, 0,
|
||
|
|
CreateCcRel, DummyDelete,
|
||
|
|
OpenCcRel, SaveCcRel,
|
||
|
|
DummyClose, DummyClone,
|
||
|
|
CastCcRel, DummySizeOf,
|
||
|
|
CheckCcRel );
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
5.13 Operator ~mconsume~
|
||
|
|
|
||
|
|
Collects objects from a stream of tuples into a
|
||
|
|
main memory relation using the ~mrel~ type constructor
|
||
|
|
of the old relational algebra.
|
||
|
|
|
||
|
|
This operator is used to convert from a relation in
|
||
|
|
the persistent relational algebra to the old one.
|
||
|
|
|
||
|
|
5.6.1 Type mapping function of operator ~mconsume~
|
||
|
|
|
||
|
|
Operator ~mconsume~ accepts a stream of tuples and returns a
|
||
|
|
main memory relation.
|
||
|
|
|
||
|
|
|
||
|
|
---- (stream tuple(x)) -> ( mrel mtuple(x) )
|
||
|
|
----
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr MConsumeTypeMap(ListExpr args)
|
||
|
|
{
|
||
|
|
|
||
|
|
if(nl->ListLength(args)!=1){
|
||
|
|
return listutils::typeError("one argument expected");
|
||
|
|
}
|
||
|
|
ListExpr first = nl->First(args);
|
||
|
|
if(!listutils::isTupleStream(nl->First(args))){
|
||
|
|
return listutils::typeError(" stream(tuple(x)) expected");
|
||
|
|
}
|
||
|
|
|
||
|
|
return nl->TwoElemList(
|
||
|
|
nl->SymbolAtom(CcRel::BasicType()),
|
||
|
|
nl->TwoElemList(
|
||
|
|
nl->SymbolAtom(CcTuple::BasicType()),
|
||
|
|
nl->Second(nl->Second(first))));
|
||
|
|
}
|
||
|
|
/*
|
||
|
|
|
||
|
|
5.6.2 Value mapping function of operator ~mconsume~
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
CcTuple *
|
||
|
|
CloneToMemoryTuple(Tuple* t)
|
||
|
|
{
|
||
|
|
Counter::getRef("RA:ClonedTuples")++;
|
||
|
|
CcTuple *result = new CcTuple();
|
||
|
|
|
||
|
|
result->SetNoAttrs( t->GetNoAttributes() );
|
||
|
|
for( int i = 0; i < t->GetNoAttributes(); i++ )
|
||
|
|
{
|
||
|
|
Attribute *attr = t->GetAttribute( i )->Clone();
|
||
|
|
result->Put( i, attr );
|
||
|
|
}
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
int
|
||
|
|
MConsume(Word* args, Word& result, int message,
|
||
|
|
Word& local, Supplier s)
|
||
|
|
{
|
||
|
|
Word actual;
|
||
|
|
CcRel* rel;
|
||
|
|
|
||
|
|
rel = (CcRel*)((qp->ResultStorage(s)).addr);
|
||
|
|
if(rel->GetNoTuples() > 0)
|
||
|
|
{
|
||
|
|
rel->Empty();
|
||
|
|
}
|
||
|
|
|
||
|
|
qp->Open(args[0].addr);
|
||
|
|
qp->Request(args[0].addr, actual);
|
||
|
|
while (qp->Received(args[0].addr))
|
||
|
|
{
|
||
|
|
CcTuple* tuple = CloneToMemoryTuple(((Tuple*)actual.addr));
|
||
|
|
rel->AppendTuple(tuple);
|
||
|
|
((Tuple*)actual.addr)->DeleteIfAllowed();
|
||
|
|
|
||
|
|
qp->Request(args[0].addr, actual);
|
||
|
|
}
|
||
|
|
|
||
|
|
result = SetWord((void*) rel);
|
||
|
|
|
||
|
|
|
||
|
|
qp->Close(args[0].addr);
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
/*
|
||
|
|
|
||
|
|
5.6.3 Specification of operator ~mconsume~
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string MConsumeSpec =
|
||
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
||
|
|
"\"Example\" ) "
|
||
|
|
"( <text>(stream tuple(x)) -> (mrel mtuple(x))</text--->"
|
||
|
|
"<text>_ mconsume</text--->"
|
||
|
|
"<text>Collects objects from a stream into an mrel."
|
||
|
|
"</text--->"
|
||
|
|
"<text>query cities feed mconsume</text--->"
|
||
|
|
") )";
|
||
|
|
|
||
|
|
/*
|
||
|
|
5.6.4 Definition of operator ~mconsume~
|
||
|
|
|
||
|
|
*/
|
||
|
|
Operator relalgmconsume (
|
||
|
|
"mconsume", // name
|
||
|
|
MConsumeSpec, // specification
|
||
|
|
MConsume, // value mapping
|
||
|
|
Operator::SimpleSelect, // trivial selection function
|
||
|
|
MConsumeTypeMap // type mapping
|
||
|
|
);
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
6 Class ~OldRelationAlgebra~
|
||
|
|
|
||
|
|
A new subclass ~OldRelationAlgebra~ 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 ~RelationAlgebra~ is defined.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
class OldRelationAlgebra : public Algebra
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
OldRelationAlgebra() : Algebra()
|
||
|
|
{
|
||
|
|
AddTypeConstructor( &ccreltuple );
|
||
|
|
AddTypeConstructor( &ccrelrel );
|
||
|
|
|
||
|
|
AddOperator(&ccrelfeed);
|
||
|
|
AddOperator(&ccrelsample);
|
||
|
|
AddOperator(&ccrelconsume);
|
||
|
|
AddOperator(&ccrelTUPLE);
|
||
|
|
AddOperator(&ccrelgroup);
|
||
|
|
AddOperator(&ccrelTUPLE2);
|
||
|
|
AddOperator(&ccrelattr);
|
||
|
|
AddOperator(&ccrelfilter);
|
||
|
|
AddOperator(&ccrelproject);
|
||
|
|
AddOperator(&ccrelremove);
|
||
|
|
AddOperator(&ccrelproduct);
|
||
|
|
AddOperator(&ccrelcancel);
|
||
|
|
AddOperator(&ccrelcount);
|
||
|
|
AddOperator(&ccrelrename);
|
||
|
|
AddOperator(&ccrelextract);
|
||
|
|
AddOperator(&ccrelextend);
|
||
|
|
AddOperator(&ccrelconcat);
|
||
|
|
AddOperator(&ccrelmax);
|
||
|
|
AddOperator(&ccrelmin);
|
||
|
|
AddOperator(&ccrelavg);
|
||
|
|
AddOperator(&ccrelsum);
|
||
|
|
AddOperator(&ccrelhead);
|
||
|
|
AddOperator(&ccrelsortby);
|
||
|
|
AddOperator(&ccrelsort);
|
||
|
|
AddOperator(&ccrelrdup);
|
||
|
|
AddOperator(&ccrelmergesec);
|
||
|
|
AddOperator(&ccrelmergediff);
|
||
|
|
AddOperator(&ccrelmergeunion);
|
||
|
|
AddOperator(&ccrelmergejoin);
|
||
|
|
AddOperator(&ccrelloopjoin);
|
||
|
|
AddOperator(&ccrelloopselect);
|
||
|
|
AddOperator(&ccrelloopjoinrel);
|
||
|
|
AddOperator(&ccrelsortmergejoin);
|
||
|
|
AddOperator(&ccrelhashjoin);
|
||
|
|
AddOperator(&ccrelgroupby);
|
||
|
|
AddOperator(&relalgmconsume);
|
||
|
|
|
||
|
|
ccreltuple.AssociateKind( "MTUPLE" );
|
||
|
|
ccrelrel.AssociateKind( "MREL" );
|
||
|
|
|
||
|
|
}
|
||
|
|
~OldRelationAlgebra() {};
|
||
|
|
};
|
||
|
|
|
||
|
|
} // end of namespace oldrelation
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
7 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*
|
||
|
|
InitializeOldRelationAlgebra( NestedList* nlRef, QueryProcessor* qpRef )
|
||
|
|
{
|
||
|
|
nl = nlRef;
|
||
|
|
qp = qpRef;
|
||
|
|
return (new oldrelation::OldRelationAlgebra());
|
||
|
|
}
|
||
|
|
|