5082 lines
127 KiB
C++
5082 lines
127 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
|
|
|
|
June 1996 Claudia Freundorfer
|
|
|
|
May 2002 Frank Hoffmann port to C++
|
|
|
|
November 7, 2002 RHG Corrected the type mapping of ~count~.
|
|
|
|
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.
|
|
|
|
March 2003 Victor Almeida created the new Relational Algebra
|
|
organization.
|
|
|
|
December 2005, Victor Almeida deleted the deprecated algebra levels
|
|
(~executable~, ~descriptive~, and ~hybrid~). Only the executable
|
|
level remains. Models are also removed from type constructors.
|
|
|
|
January 2006 Victor Almeida replaced the ~free~ tuples concept to
|
|
reference counters. There are reference counters on tuples and also
|
|
on attributes. Some assertions were removed, since the code is
|
|
stable.
|
|
|
|
April 2006, M. Spiekermann. New operators ~dumpstream~ and ~sizecounters~
|
|
added.
|
|
|
|
[TOC]
|
|
|
|
1 Overview
|
|
|
|
The Relational Algebra basically implements two type constructors,
|
|
namely ~tuple~ and ~rel~.
|
|
|
|
More information about the Relational Algebra can be found in the
|
|
RelationAlgebra.h header file.
|
|
|
|
2 Defines, includes, and constants
|
|
|
|
*/
|
|
#include "RelationAlgebra.h"
|
|
#include "Algebras/OrderedRelation/OrderedRelationAlgebra.h"
|
|
#include "NestedList.h"
|
|
#include "QueryProcessor.h"
|
|
#include "Algebra.h"
|
|
#include "StandardTypes.h"
|
|
#include "Progress.h"
|
|
#include "Algebras/FText/FTextAlgebra.h"
|
|
|
|
#include "LogMsg.h"
|
|
#include "NList.h"
|
|
#include "ListUtils.h"
|
|
#include "Symbols.h"
|
|
#include "Stream.h"
|
|
|
|
#ifdef USE_PROGRESS
|
|
#include "../CostEstimation/RelationAlgebraCostEstimation.h"
|
|
#endif
|
|
|
|
#include "OperatorConsume.h"
|
|
#include "OperatorFeed.h"
|
|
#include "OperatorFilter.h"
|
|
#include "OperatorProject.h"
|
|
#include "OperatorFeedProject.h"
|
|
#include "Messages.h"
|
|
|
|
extern NestedList* nl;
|
|
extern QueryProcessor* qp;
|
|
extern AlgebraManager *am;
|
|
|
|
using namespace std;
|
|
|
|
/*
|
|
3 Type constructor ~tuple~
|
|
|
|
The list representation of a tuple is:
|
|
|
|
---- (<attrrep 1> ... <attrrep n>)
|
|
----
|
|
|
|
Typeinfo is:
|
|
|
|
---- (<NumericType(<type exression>)> <number of attributes>)
|
|
----
|
|
|
|
|
|
For example, for
|
|
|
|
---- (tuple
|
|
(
|
|
(name string)
|
|
(age int)))
|
|
----
|
|
|
|
the typeinfo is
|
|
|
|
---- (
|
|
(2 2)
|
|
(
|
|
(name (1 4))
|
|
(age (1 1))))
|
|
----
|
|
|
|
The typeinfo list consists of three lists. The first list is a
|
|
pair (~algebraId~, ~typeId~). The second list represents the
|
|
attribute list of the tuple. This list is a sequence of pairs
|
|
(~attribute\_name~ (~algebraId~ ~typeId~)). Here the
|
|
~typeId~ is the identificator of a standard data type, e.g. int.
|
|
The third list is an atom and counts the number of the
|
|
tuple's attributes.
|
|
|
|
3.1 Type property of type constructor ~tuple~
|
|
|
|
*/
|
|
ListExpr TupleProp ()
|
|
{
|
|
ListExpr examplelist = nl->TextAtom();
|
|
nl->AppendText(examplelist,"(\"Myers\" 53)");
|
|
|
|
return (nl->TwoElemList(
|
|
nl->FourElemList(
|
|
nl->StringAtom("Signature"),
|
|
nl->StringAtom("Example Type List"),
|
|
nl->StringAtom("List Rep"),
|
|
nl->StringAtom("Example List")),
|
|
nl->FourElemList(
|
|
nl->StringAtom("(ident x DATA)+ -> TUPLE"),
|
|
nl->StringAtom("(tuple((name string)(age int)))"),
|
|
nl->StringAtom("(<attr1> ... <attrn>)"),
|
|
examplelist)));
|
|
}
|
|
|
|
/*
|
|
3.2 ~Out~-function of type constructor ~tuple~
|
|
|
|
The ~out~-function of type constructor ~tuple~ takes as inputs a
|
|
type description (~typeInfo~) of the tuple's attribute structure in
|
|
nested list format and a pointer to a tuple value, stored in main
|
|
memory. The function returns the tuple value in nested list format.
|
|
|
|
*/
|
|
ListExpr
|
|
OutTuple (ListExpr typeInfo, Word value)
|
|
{
|
|
return ((Tuple *)value.addr)->Out( typeInfo );
|
|
}
|
|
|
|
/*
|
|
3.3 ~SaveToList~-function of type constructor ~tuple~
|
|
|
|
The ~SaveToList~-function should act as the ~Out~-function
|
|
but using internal representation of the objects. It is called
|
|
by the default persistence mechanism to store the objects in
|
|
the database.
|
|
|
|
*/
|
|
ListExpr
|
|
SaveToListTuple (ListExpr typeInfo, Word value)
|
|
{
|
|
return ((Tuple *)value.addr)->SaveToList( typeInfo );
|
|
}
|
|
|
|
/*
|
|
3.3 ~In~-function of type constructor ~tuple~
|
|
|
|
The ~In~-function of type constructor ~tuple~ takes as inputs a
|
|
type description (~typeInfo~) of the tuples attribute structure in
|
|
nested list format and the tuple value in nested list format. The
|
|
function returns a pointer to a tuple value, stored in main memory
|
|
in accordance to the tuple value in nested list format.
|
|
|
|
Error handling in ~InTuple~: ~correct~ is only true if there is the
|
|
right number of attribute values and all values have correct list
|
|
representations.
|
|
|
|
Otherwise the following error messages are added to ~errorInfo~:
|
|
|
|
---- (71 tuple 1 <errorPos>) atom instead of value list
|
|
(71 tuple 2 <errorPos>) not enough values
|
|
(71 tuple 3 <errorPos> <attrno>) wrong attribute value in
|
|
attribute <attrno>
|
|
(71 tuple 4 <errorPos>) too many values
|
|
----
|
|
|
|
is added to ~errorInfo~. Here ~errorPos~ is the number of the tuple
|
|
in the relation list (passed by ~InRelation~).
|
|
|
|
|
|
*/
|
|
Word
|
|
InTuple(ListExpr typeInfo, ListExpr value,
|
|
int errorPos, ListExpr& errorInfo, bool& correct)
|
|
{
|
|
return SetWord( Tuple::In( typeInfo, value, errorPos,
|
|
errorInfo, correct ) );
|
|
}
|
|
|
|
/*
|
|
3.3 ~RestoreFromList~-function of type constructor ~tuple~
|
|
|
|
The ~RestoreFromList~-function should act as the ~In~-function
|
|
but using internal representation of the objects. It is called
|
|
by the default persistence mechanism to retrieve the objects in
|
|
the database.
|
|
|
|
*/
|
|
Word
|
|
RestoreFromListTuple(ListExpr typeInfo, ListExpr value,
|
|
int errorPos, ListExpr& errorInfo,
|
|
bool& correct)
|
|
{
|
|
return
|
|
SetWord( Tuple::RestoreFromList( typeInfo, value, errorPos,
|
|
errorInfo, correct ) );
|
|
}
|
|
|
|
/*
|
|
3.4 ~Delete~-function of type constructor ~tuple~
|
|
|
|
A type constructor's ~delete~-function is used by the query
|
|
processor in order to deallocate memory occupied by instances
|
|
of Secondo objects. They may have been created in two ways:
|
|
|
|
* as return values of operator calls
|
|
|
|
* by calling a type constructor's ~create~-function.
|
|
|
|
*/
|
|
void DeleteTuple(const ListExpr typeInfo, Word& w)
|
|
{
|
|
((Tuple *)w.addr)->DeleteIfAllowed();
|
|
}
|
|
|
|
/*
|
|
|
|
3.5 ~Check~-function of type constructor ~tuple~
|
|
|
|
Checks the specification:
|
|
|
|
---- (ident x DATA)+ -> TUPLE tuple
|
|
----
|
|
|
|
with the additional constraint that all identifiers used (attribute
|
|
names) must be distinct. Hence a tuple type has the form:
|
|
|
|
---- (tuple
|
|
(
|
|
(age x)
|
|
(name y)))
|
|
----
|
|
|
|
and ~x~ and ~y~ must be types of kind DATA. Kind TUPLE introduces
|
|
the following error codes:
|
|
|
|
---- (... 1) Empty tuple type
|
|
(... 2 x) x is not an attribute list, but an atom
|
|
(... 3 x) Doubly defined attribute name x
|
|
(... 4 x) Invalid attribute name x
|
|
(... 5 x) Invalid attribute definition x (x is not a pair)
|
|
(... 6 x) Attribute type does not belong to kind DATA
|
|
----
|
|
|
|
*/
|
|
bool
|
|
CheckTuple(ListExpr type, ListExpr& errorInfo)
|
|
{
|
|
if(!Tuple::checkType(type)){
|
|
return false;
|
|
}
|
|
|
|
if(!listutils::checkAttrListForNamingConventions(nl->Second(type))){
|
|
cmsg.typeError("Attribute names do not fit Secondo's name conventions\n"
|
|
"(an attribute name must start with a capital letter.)\n");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
3.6 ~Cast~-function of type constructor ~tuple~
|
|
|
|
Casts a tuple from a stream representation of it. This function is
|
|
used to read objects from the disk by the ~TupleManager~. Since
|
|
tuples are not part of tuples the implementation of this function
|
|
is not necessary.
|
|
|
|
*/
|
|
void*
|
|
CastTuple(void* addr)
|
|
{
|
|
return ( 0 );
|
|
}
|
|
|
|
/*
|
|
3.7 ~Create~-function of type constructor ~tuple~
|
|
|
|
This function is used to allocate memory sufficient for keeping one
|
|
instance of ~tuple~.
|
|
|
|
*/
|
|
Word
|
|
CreateTuple(const ListExpr typeInfo)
|
|
{
|
|
TupleType* tt = new TupleType(nl->Second(typeInfo));
|
|
Tuple *tup = new Tuple( tt );
|
|
tt->DeleteIfAllowed();
|
|
return (SetWord(tup));
|
|
}
|
|
|
|
/*
|
|
3.8 ~Close~-function of type constructor ~tuple~
|
|
|
|
This function is used to destroy the memory allocated by a ~tuple~.
|
|
|
|
*/
|
|
void CloseTuple(const ListExpr typeInfo, Word& w)
|
|
{
|
|
((Tuple *)w.addr)->DeleteIfAllowed();
|
|
}
|
|
|
|
/*
|
|
3.9 ~Clone~-function of type constructor ~tuple~
|
|
|
|
This function creates a cloned tuple.
|
|
|
|
*/
|
|
Word
|
|
CloneTuple(const ListExpr typeInfo, const Word& w)
|
|
{
|
|
return SetWord( ((Tuple *)w.addr)->Clone() );
|
|
}
|
|
|
|
/*
|
|
3.10 ~Sizeof~-function of type constructor ~tuple~
|
|
|
|
Returns the size of a tuple's root record to be stored on the disk
|
|
as a stream. Since tuples are not part of tuples, the implementation
|
|
of this function is not necessary.
|
|
|
|
*/
|
|
int
|
|
SizeOfTuple()
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
3.12 Definition of type constructor ~tuple~
|
|
|
|
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 cpptuple( Tuple::BasicType(), TupleProp,
|
|
OutTuple, InTuple,
|
|
SaveToListTuple, RestoreFromListTuple,
|
|
CreateTuple, DeleteTuple,
|
|
0, 0,
|
|
CloseTuple, CloneTuple,
|
|
CastTuple, SizeOfTuple,
|
|
CheckTuple );
|
|
/*
|
|
4 TypeConstructor ~rel~
|
|
|
|
The list representation of a relation is:
|
|
|
|
---- (<tuplerep 1> ... <tuplerep n>)
|
|
----
|
|
|
|
Typeinfo is:
|
|
|
|
---- (<NumericType(<type exression>)>)
|
|
----
|
|
|
|
For example, for
|
|
|
|
---- (rel (tuple ((name string) (age int))))
|
|
----
|
|
|
|
the type info is
|
|
|
|
---- ((2 1) ((2 2) ((name (1 4)) (age (1 1)))))
|
|
----
|
|
|
|
4.1 Type property of type constructor ~rel~
|
|
|
|
*/
|
|
ListExpr RelProp ()
|
|
{
|
|
ListExpr listreplist = nl->TextAtom();
|
|
ListExpr examplelist = nl->TextAtom();
|
|
nl->AppendText(listreplist,"(<tuple>*)where <tuple> is "
|
|
"(<attr1> ... <attrn>)");
|
|
nl->AppendText(examplelist,"((\"Myers\" 53)(\"Smith\" 21))");
|
|
|
|
return nl->TwoElemList(
|
|
nl->FourElemList(
|
|
nl->StringAtom("Signature"),
|
|
nl->StringAtom("Example Type List"),
|
|
nl->StringAtom("List Rep"),
|
|
nl->StringAtom("Example List")),
|
|
nl->FourElemList(
|
|
nl->StringAtom("TUPLE -> REL"),
|
|
nl->StringAtom("(rel(tuple((name string)(age int))))"),
|
|
listreplist,
|
|
examplelist));
|
|
}
|
|
|
|
/*
|
|
4.2 ~Out~-function of type constructor ~rel~
|
|
|
|
*/
|
|
ListExpr
|
|
OutRel(ListExpr typeInfo, Word value)
|
|
{
|
|
Relation* rel = ((Relation *)value.addr);
|
|
return rel->Out( typeInfo, rel->MakeScan() );
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
4.3 ~SaveToList~-function of type constructor ~rel~
|
|
|
|
The ~SaveToList~-function should act as the ~Out~-function
|
|
but using internal representation of the objects. It is called
|
|
by the default persistence mechanism to store the objects in
|
|
the database.
|
|
|
|
*/
|
|
ListExpr
|
|
SaveToListRel(ListExpr typeInfo, Word value)
|
|
{
|
|
return ((Relation *)value.addr)->SaveToList( typeInfo );
|
|
}
|
|
|
|
/*
|
|
4.3 ~Create~-function of type constructor ~rel~
|
|
|
|
The function is used to allocate memory sufficient for keeping one
|
|
instance of ~rel~.
|
|
|
|
*/
|
|
Word
|
|
CreateRel(const ListExpr typeInfo)
|
|
{
|
|
//cerr << "CreateRel: " << nl->ToString(typeInfo) << endl;
|
|
Relation* rel = new Relation( typeInfo );
|
|
return (SetWord(rel));
|
|
}
|
|
|
|
/*
|
|
4.4 ~In~-function of type constructor ~rel~
|
|
|
|
~value~ is the list representation of the relation. The structure
|
|
of ~typeInfo~ and ~value~ are described above. Error handling in
|
|
~InRel~:
|
|
|
|
The result relation will contain all tuples that have been converted
|
|
correctly (have correct list expressions). For all other tuples, an
|
|
error message containing the position of the tuple within this
|
|
relation (list) is added to ~errorInfo~. (This is done by
|
|
procedure ~InTuple~ called by ~InRel~). If any tuple representation
|
|
is wrong, then ~InRel~ will return ~correct~ as FALSE and will
|
|
itself add an error message of the form
|
|
|
|
---- (InRel <errorPos>)
|
|
----
|
|
|
|
to ~errorInfo~. The value in ~errorPos~ has to be passed from the
|
|
environment; probably it is the position of the relation object in
|
|
the list of database objects.
|
|
|
|
*/
|
|
Word
|
|
InRel(ListExpr typeInfo, ListExpr value,
|
|
int errorPos, ListExpr& errorInfo, bool& correct)
|
|
{
|
|
return SetWord( Relation::In( typeInfo, value, errorPos,
|
|
errorInfo, correct ) );
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
4.3 ~RestoreFromList~-function of type constructor ~rel~
|
|
|
|
The ~RestoreFromList~-function should act as the ~In~-function
|
|
but using internal representation of the objects. It is called
|
|
by the default persistence mechanism to retrieve the objects in
|
|
the database.
|
|
|
|
*/
|
|
Word
|
|
RestoreFromListRel(ListExpr typeInfo, ListExpr value,
|
|
int errorPos, ListExpr& errorInfo, bool& correct)
|
|
{
|
|
return
|
|
SetWord( Relation::RestoreFromList( typeInfo, value, errorPos,
|
|
errorInfo, correct ) );
|
|
}
|
|
|
|
/*
|
|
4.5 ~Delete~-function of type constructor ~rel~
|
|
|
|
*/
|
|
void DeleteRel(const ListExpr typeInfo, Word& w)
|
|
{
|
|
((Relation *)w.addr)->Delete();
|
|
w.addr = 0;
|
|
}
|
|
|
|
/*
|
|
4.6 ~Check~-function of type constructor ~rel~
|
|
|
|
Checks the specification:
|
|
|
|
---- TUPLE -> REL rel
|
|
----
|
|
|
|
Hence the type expression must have the form
|
|
|
|
---- (rel x)
|
|
----
|
|
|
|
and ~x~ must be a type of kind TUPLE.
|
|
|
|
*/
|
|
bool
|
|
CheckRel(ListExpr type, ListExpr& errorInfo)
|
|
{
|
|
if ((nl->ListLength(type) == 2) &&
|
|
nl->IsEqual(nl->First(type), Relation::BasicType()))
|
|
{
|
|
return am->CheckKind(Kind::TUPLE(), nl->Second(type), errorInfo);
|
|
}
|
|
else
|
|
{
|
|
errorInfo = nl->Append(errorInfo,
|
|
nl->ThreeElemList(
|
|
nl->IntAtom(60),
|
|
nl->SymbolAtom("REL"),
|
|
type));
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/*
|
|
4.7 ~Cast~-function of type constructor ~rel~
|
|
|
|
*/
|
|
void*
|
|
CastRel(void* addr)
|
|
{
|
|
return ( 0 );
|
|
}
|
|
|
|
/*
|
|
4.8 ~Close~-function of type constructor ~rel~
|
|
|
|
There is a cache of relations in order to increase performance.
|
|
The cache is responsible for closing the relations.
|
|
In this case we will implement one function that does nothing,
|
|
called ~CloseRel~ and another which the cache will execute, called
|
|
~CacheCloseRel~.
|
|
|
|
*/
|
|
void CloseRel(const ListExpr typeInfo, Word& w)
|
|
{
|
|
return ((Relation *)w.addr)->Close();
|
|
}
|
|
|
|
/*
|
|
4.9 ~Open~-function of type constructor ~rel~
|
|
|
|
This is a slightly modified version of the function ~DefaultOpen~
|
|
(from ~Algebra~) which creates the relation from the SmiRecord only
|
|
if it does not yet exist.
|
|
|
|
The idea is to maintain a cache containing the relation
|
|
representations that have been built in memory. The cache basically
|
|
stores pairs (~recordId~, ~relation\_value~). If the ~recordId~
|
|
passed to this function is found, the cached relation value is
|
|
returned instead of building a new one.
|
|
|
|
*/
|
|
bool
|
|
OpenRel( SmiRecord& valueRecord,
|
|
size_t& offset,
|
|
const ListExpr typeInfo,
|
|
Word& value )
|
|
{
|
|
value.setAddr( Relation::Open( valueRecord, offset, typeInfo ) );
|
|
return value.addr != 0;
|
|
}
|
|
|
|
/*
|
|
4.10 ~Save~-function of type constructor ~rel~
|
|
|
|
*/
|
|
bool
|
|
SaveRel( SmiRecord& valueRecord,
|
|
size_t& offset,
|
|
const ListExpr typeInfo,
|
|
Word& value )
|
|
{
|
|
return
|
|
((Relation *)value.addr)->Save( valueRecord, offset, typeInfo );
|
|
}
|
|
|
|
/*
|
|
4.11 ~Sizeof~-function of type constructor ~rel~
|
|
|
|
*/
|
|
int
|
|
SizeOfRel()
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
4.12 ~Clone~-function of type constructor ~rel~
|
|
|
|
*/
|
|
Word
|
|
CloneRel(const ListExpr typeInfo, const Word& w)
|
|
{
|
|
return SetWord( ((Relation*)w.addr)->Clone() );
|
|
}
|
|
|
|
/*
|
|
|
|
4.14 Definition of type constructor ~rel~
|
|
|
|
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 cpprel( Relation::BasicType(), RelProp,
|
|
OutRel, InRel,
|
|
SaveToListRel, RestoreFromListRel,
|
|
CreateRel, DeleteRel,
|
|
OpenRel, SaveRel,
|
|
CloseRel, CloneRel,
|
|
CastRel, SizeOfRel,
|
|
CheckRel );
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
4 Type constructor ~trel~
|
|
|
|
A ~trel~ is represented as a tuple buffer. It re-uses the in and out functions of class
|
|
relation.
|
|
|
|
*/
|
|
|
|
class TmpRel {
|
|
|
|
public:
|
|
TmpRel(){ };
|
|
~TmpRel(){};
|
|
|
|
static GenericRelation* In( ListExpr typeInfo,
|
|
ListExpr value,
|
|
int errorPos,
|
|
ListExpr& errorInfo,
|
|
bool& correct ) {
|
|
|
|
// the last parameter of Relation::In indicates that a
|
|
// TupleBuffer instance should be created.
|
|
GenericRelation* r =
|
|
(GenericRelation*)Relation::In( typeInfo, value,
|
|
errorPos, errorInfo,
|
|
correct, true);
|
|
return r;
|
|
}
|
|
|
|
};
|
|
|
|
|
|
ListExpr
|
|
OutTmpRel(ListExpr typeInfo, Word value)
|
|
{
|
|
GenericRelation* rel = ((Relation *)value.addr);
|
|
return Relation::Out( typeInfo, rel->MakeScan() );
|
|
}
|
|
|
|
Word
|
|
InTmpRel(ListExpr typeInfo, ListExpr value,
|
|
int errorPos, ListExpr& errorInfo, bool& correct)
|
|
{
|
|
return SetWord( TmpRel::In( typeInfo, value, errorPos,
|
|
errorInfo, correct ) );
|
|
}
|
|
|
|
Word CreateTmpRel( const ListExpr typeInfo )
|
|
{
|
|
return (SetWord( new TupleBuffer() ));
|
|
}
|
|
|
|
void DeleteTmpRel( const ListExpr, Word& w )
|
|
{
|
|
delete (TupleBuffer *)w.addr;
|
|
w.addr = 0;
|
|
}
|
|
|
|
|
|
bool
|
|
TRelKindCheck( ListExpr type, ListExpr& errorInfo ){
|
|
return listutils::isRelDescription(type,true);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
5 Operators
|
|
|
|
5.2 Selection function for type operators
|
|
|
|
The selection function of a type operator always returns -1.
|
|
|
|
*/
|
|
int TypeOperatorSelect(ListExpr args)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
5.3 Type Operator ~TUPLE~
|
|
|
|
Type operators are used only for inferring argument types of
|
|
parameter functions. They have a type mapping but no evaluation
|
|
function.
|
|
|
|
5.3.1 Type mapping function of operator ~TUPLE~
|
|
|
|
Extract tuple type from a stream or relation type given as the
|
|
first argument.
|
|
|
|
---- ((stream x) ...) -> x
|
|
((rel x) ...) -> x
|
|
((orel x) ...) -> x
|
|
----
|
|
|
|
*/
|
|
ListExpr TUPLETypeMap(ListExpr args)
|
|
{
|
|
if(nl->ListLength(args)<1){
|
|
ErrorReporter::ReportError("One argument expected");
|
|
return nl->TypeError();
|
|
}
|
|
ListExpr first = nl->First(args);
|
|
if(listutils::isTupleStream(first) ||
|
|
listutils::isRelDescription(first) ||
|
|
listutils::isOrelDescription(first) ){
|
|
return nl->Second(first);
|
|
}
|
|
ErrorReporter::ReportError("rel(tuple(...)) or stream(tuple(...))) expected");
|
|
return nl->TypeError();
|
|
}
|
|
/*
|
|
|
|
5.3.2 Specification of operator ~TUPLE~
|
|
|
|
*/
|
|
const string TUPLESpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
|
"\"Remarks\" ) "
|
|
"( <text>((stream x)...) -> x, ((rel 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--->"
|
|
" ) )";
|
|
|
|
/*
|
|
|
|
5.3.3 Definition of operator ~TUPLE~
|
|
|
|
*/
|
|
Operator relalgTUPLE (
|
|
"TUPLE", // name
|
|
TUPLESpec, // specification
|
|
0, // no value mapping
|
|
TypeOperatorSelect, // trivial selection function
|
|
TUPLETypeMap // type mapping
|
|
);
|
|
/*
|
|
|
|
5.4 Type Operator ~TUPLE2~
|
|
|
|
5.4.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
|
|
((rel x) (rel y) ...) -> y
|
|
----
|
|
|
|
*/
|
|
ListExpr TUPLE2TypeMap(ListExpr args)
|
|
{
|
|
ListExpr second;
|
|
if(nl->ListLength(args) >= 2) {
|
|
second = nl->Second(args);
|
|
if(nl->ListLength(second) == 2 ) {
|
|
if(Stream<ANY>::checkType(second)
|
|
|| Relation::checkType(second)){
|
|
return nl->Second(second);
|
|
}
|
|
}
|
|
}
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
|
}
|
|
/*
|
|
|
|
5.4.2 Specification of operator ~TUPLE2~
|
|
|
|
*/
|
|
const string TUPLE2Spec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
|
"\"Remarks\" ) "
|
|
"( <text><text>((stream x) (stream y) ...) -> y, "
|
|
"((rel x) (rel 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--->"
|
|
") )";
|
|
|
|
/*
|
|
|
|
5.4.3 Definition of operator ~TUPLE2~
|
|
|
|
*/
|
|
Operator relalgTUPLE2 (
|
|
"TUPLE2", // name
|
|
TUPLE2Spec, // specification
|
|
0, // no value mapping
|
|
TypeOperatorSelect, // trivial selection function
|
|
TUPLE2TypeMap // type mapping
|
|
);
|
|
|
|
/*
|
|
|
|
5.5.3 Specification of operator ~feed~
|
|
|
|
*/
|
|
|
|
const string FeedSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
|
"\"Example\" ) "
|
|
"( <text>rel(X) | trel(X) | orel(X,Y) -> stream(X)</text--->"
|
|
"<text>_ feed</text--->"
|
|
"<text>Produces a stream from a relation, temporal relation, or ordered "
|
|
"relation by scanning the relation tuple by tuple.</text--->"
|
|
"<text>query cities feed consume</text--->"
|
|
") )";
|
|
|
|
/*
|
|
|
|
5.5.4 Definition of operator ~feed~
|
|
|
|
Non-overloaded operators are defined by constructing a new instance
|
|
of class ~Operator~, passing all operator functions as constructor
|
|
arguments.
|
|
|
|
*/
|
|
|
|
#ifdef USE_PROGRESS
|
|
Operator relalgfeed (
|
|
"feed", // name
|
|
FeedSpec, // specification
|
|
OperatorFeed::Feed, // value mapping
|
|
Operator::SimpleSelect, // trivial selection function
|
|
OperatorFeed::FeedTypeMap, // type mapping
|
|
OperatorFeed::FeedCostEstimationFunc // CostEstimation
|
|
);
|
|
#else
|
|
Operator relalgfeed (
|
|
"feed", // name
|
|
FeedSpec, // specification
|
|
OperatorFeed::Feed, // value mapping
|
|
Operator::SimpleSelect, // trivial selection function
|
|
OperatorFeed::FeedTypeMap // type mapping
|
|
);
|
|
#endif
|
|
|
|
/*
|
|
5.6.3 Specification of operator ~consume~
|
|
|
|
*/
|
|
const string ConsumeSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
|
"\"Example\" ) "
|
|
"( <text>(stream x) -> (rel x)</text--->"
|
|
"<text>_ consume</text--->"
|
|
"<text>Collects objects from a stream."
|
|
"</text--->"
|
|
"<text>query cities feed consume</text--->"
|
|
") )";
|
|
|
|
const string OConsumeSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
|
"\"Example\" ) "
|
|
"( <text>(stream (tuple(a1:t1 ... an:tn) x (ai aj ak) -> "
|
|
"(orel (tuple(a1:t1 ... an:tn)) (ai aj ak))</text--->"
|
|
"<text>_ oconsume [list]</text--->"
|
|
"<text>Collects objects from a stream and sorts them according to the second"
|
|
" argument.</text--->"
|
|
"<text>query cities feed oconsume [BevT,Name]</text--->"
|
|
") )";
|
|
|
|
|
|
const string TConsumeSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
|
"\"Example\" ) "
|
|
"( <text> stream(tuple(...)) -> trel(tuple(...))</text--->"
|
|
"<text>_ tconsume </text--->"
|
|
"<text> Appends the tuples' values into a tuple buffer."
|
|
"The result cant be materialized, thus don't "
|
|
" </text--->"
|
|
"<text>query cities feed tconsume</text--->"
|
|
") )";
|
|
|
|
/*
|
|
|
|
5.6.4 Definition of operator ~consume~
|
|
|
|
*/
|
|
#ifdef USE_PROGRESS
|
|
Operator relalgconsume (
|
|
"consume", // name
|
|
ConsumeSpec, // specification
|
|
OperatorConsume::Consume, // value mapping
|
|
Operator::SimpleSelect, // trivial selection function
|
|
OperatorConsume::ConsumeTypeMap<false>, // type mapping
|
|
OperatorConsume::ConsumeCostEstimationFunc // cost estimation
|
|
);
|
|
|
|
Operator relalgoconsume (
|
|
"oconsume", // name
|
|
OConsumeSpec, // specification
|
|
OperatorConsume::Consume, // value mapping
|
|
Operator::SimpleSelect, // trivial selection function
|
|
OperatorConsume::ConsumeTypeMap<true>, // type mapping
|
|
OperatorConsume::ConsumeCostEstimationFunc // Const estimation
|
|
);
|
|
|
|
Operator relalgtconsume (
|
|
"tconsume", // name
|
|
TConsumeSpec, // specification
|
|
OperatorConsume::Consume, // value mapping
|
|
Operator::SimpleSelect, // trivial selection function
|
|
OperatorConsume::tconsume_tm, // type mapping
|
|
OperatorConsume::ConsumeCostEstimationFunc // Cost estimation
|
|
);
|
|
#else
|
|
Operator relalgconsume (
|
|
"consume", // name
|
|
ConsumeSpec, // specification
|
|
OperatorConsume::Consume, // value mapping
|
|
Operator::SimpleSelect, // trivial selection function
|
|
OperatorConsume::ConsumeTypeMap<false> // type mapping
|
|
);
|
|
|
|
Operator relalgoconsume (
|
|
"oconsume", // name
|
|
OConsumeSpec, // specification
|
|
OperatorConsume::Consume, // value mapping
|
|
Operator::SimpleSelect, // trivial selection function
|
|
OperatorConsume::ConsumeTypeMap<true> // type mapping
|
|
);
|
|
|
|
|
|
Operator relalgtconsume (
|
|
"tconsume", // name
|
|
TConsumeSpec, // specification
|
|
OperatorConsume::Consume, // value mapping
|
|
Operator::SimpleSelect, // trivial selection function
|
|
OperatorConsume::tconsume_tm // type mapping
|
|
);
|
|
#endif
|
|
|
|
/*
|
|
5.7 Operator ~attr~
|
|
|
|
5.7.1 Type mapping function of operator ~attr~
|
|
|
|
Result type attr operation.
|
|
|
|
----
|
|
((tuple ((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 index 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 "string" as the result type of the ~attr~ operation.
|
|
|
|
*/
|
|
ListExpr AttrTypeMap(ListExpr args)
|
|
{
|
|
if(nl->ListLength(args)!=2){
|
|
return listutils::typeError("two arguments expected");
|
|
}
|
|
ListExpr first = nl->First(args);
|
|
if(!Tuple::checkType(first)){
|
|
return listutils::typeError("First arguments must be tuple(...)");
|
|
}
|
|
ListExpr second = nl->Second(args);
|
|
if(!listutils::isSymbol(second)){
|
|
return listutils::typeError("second arguments ust be an attribute name");
|
|
}
|
|
|
|
string name = nl->SymbolValue(second);
|
|
ListExpr attrtype;
|
|
int j = listutils::findAttribute(nl->Second(first),name,attrtype);
|
|
if(j==0){
|
|
ErrorReporter::ReportError("Attr name " + name +
|
|
" not found in attribute list");
|
|
return nl->TypeError();
|
|
}
|
|
return nl->ThreeElemList(nl->SymbolAtom(Symbol::APPEND()),
|
|
nl->OneElemList(nl->IntAtom(j)),
|
|
attrtype);
|
|
}
|
|
/*
|
|
5.7.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]~ .
|
|
|
|
*/
|
|
int
|
|
Attr(Word* args, Word& result, int message, Word& local, Supplier s)
|
|
{
|
|
Tuple* tupleptr;
|
|
int index;
|
|
|
|
tupleptr = (Tuple*)args[0].addr;
|
|
index = ((CcInt*)args[2].addr)->GetIntval();
|
|
assert( 1 <= index && index <= tupleptr->GetNoAttributes() );
|
|
result.setAddr(tupleptr->GetAttribute(index - 1));
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
5.7.3 Specification of operator ~attr~
|
|
|
|
*/
|
|
const string AttrSpec =
|
|
"( ( \"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--->"
|
|
") )";
|
|
|
|
/*
|
|
5.7.4 Definition of operator ~attr~
|
|
|
|
*/
|
|
Operator relalgattr (
|
|
"attr", // name
|
|
AttrSpec, // specification
|
|
Attr, // value mapping
|
|
Operator::SimpleSelect, // trivial selection function
|
|
AttrTypeMap // type mapping
|
|
);
|
|
|
|
/*
|
|
5.8.3 Specification of operator ~filter~
|
|
|
|
*/
|
|
const string FilterSpec =
|
|
"( ( \"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--->"
|
|
") )";
|
|
|
|
/*
|
|
|
|
5.8.4 Definition of operator ~filter~
|
|
|
|
*/
|
|
Operator relalgfilter (
|
|
"filter", // name
|
|
FilterSpec, // specification
|
|
OperatorFilter::Filter, // value mapping
|
|
Operator::SimpleSelect, // trivial selection function
|
|
OperatorFilter::FilterTypeMap, // type mapping
|
|
OperatorFilter::FilterCostEstimationFunc // cost estimation
|
|
);
|
|
|
|
|
|
/*
|
|
5.8 Operator ~reduce~
|
|
|
|
A fraction of tuples, fulfilling a certain condition are removed from the output stream.
|
|
|
|
5.8.1 Type mapping function of operator ~reduce~
|
|
|
|
Result type of filter operation.
|
|
|
|
---- ((stream (tuple x)) (map (tuple x) bool) int)
|
|
-> (stream (tuple x))
|
|
----
|
|
|
|
5.12.0 Specification
|
|
|
|
*/
|
|
|
|
struct ReduceInfo : OperatorInfo {
|
|
|
|
ReduceInfo() : OperatorInfo()
|
|
{
|
|
name = "reduce";
|
|
signature = "stream(tuple(y)) x (stream(tuple(y)) -> bool) x int \n"
|
|
"-> stream(tuple(y))";
|
|
syntax = "_ reduce[ f, n ]";
|
|
meaning = "Passes all tuples t with f(t)=FALSE to the output stream "
|
|
"but only every k-th tuple [k=max(n,1)] which fulfills f.";
|
|
example = "plz feed reduce[.PLZ > 50000, 2] count";
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
ListExpr reduce_tm(ListExpr args)
|
|
{
|
|
|
|
if(nl->ListLength(args)!=3){
|
|
ErrorReporter::ReportError("three arguments expected");
|
|
return nl->TypeError();
|
|
}
|
|
ListExpr first = nl->First(args);
|
|
ListExpr second = nl->Second(args);
|
|
ListExpr third = nl->Third(args);
|
|
|
|
if(!listutils::isTupleStream(first)){
|
|
ErrorReporter::ReportError("first arguments must be a tuple stream");
|
|
return nl->TypeError();
|
|
}
|
|
|
|
if(!listutils::isMap<1>(second)){
|
|
ErrorReporter::ReportError("second argument must be a map");
|
|
return nl->TypeError();
|
|
}
|
|
|
|
if(!nl->IsEqual(nl->Third(second),CcBool::BasicType())){
|
|
ErrorReporter::ReportError("resulttype of the map (2. arg) must be bool");
|
|
return nl->TypeError();
|
|
}
|
|
|
|
if(!nl->Equal(nl->Second(first), nl->Second(second))){
|
|
ErrorReporter::ReportError("different typle types in stream and map");
|
|
return nl->TypeError();
|
|
}
|
|
|
|
if(!nl->IsEqual(third,CcInt::BasicType())){
|
|
ErrorReporter::ReportError("third argument must be of type int");
|
|
return nl->TypeError();
|
|
}
|
|
|
|
return first;
|
|
}
|
|
|
|
/*
|
|
5.8.2 Value mapping function of operator ~reduce~
|
|
|
|
*/
|
|
int
|
|
reduce_vm( Word* args, Word& result, int message,
|
|
Word& local, Supplier s)
|
|
{
|
|
// args[0] : stream(tuple(y))
|
|
// args[1] : stream(tuple(y)) -> bool
|
|
// args[2] : int
|
|
|
|
struct ReduceInfo {
|
|
|
|
int m;
|
|
int n;
|
|
|
|
ReduceInfo(const int ctr) : m( max(ctr-1,0) ), n(m) {}
|
|
~ReduceInfo(){}
|
|
|
|
bool passOver()
|
|
{
|
|
if (n == 0)
|
|
{
|
|
n = m;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
n--;
|
|
return false;
|
|
}
|
|
}
|
|
};
|
|
|
|
ReduceInfo* ri = static_cast<ReduceInfo*>( local.addr);
|
|
|
|
switch ( message )
|
|
{
|
|
|
|
case OPEN:
|
|
|
|
qp->Open (args[0].addr);
|
|
local.addr = new ReduceInfo(StdTypes::GetInt(args[2]));
|
|
return 0;
|
|
|
|
case REQUEST: {
|
|
|
|
Tuple* tuple = 0;
|
|
bool ok = false;
|
|
while ( true )
|
|
{
|
|
Word elem, funresult;
|
|
tuple = 0;
|
|
qp->Request(args[0].addr, elem);
|
|
ok = qp->Received(args[0].addr);
|
|
|
|
if ( !ok ) // no more tuple in the stream
|
|
break;
|
|
|
|
// apply the parameter function
|
|
ArgVectorPointer funargs;
|
|
funargs = qp->Argument(args[1].addr);
|
|
tuple = (Tuple*)elem.addr;
|
|
(*funargs)[0] = elem;
|
|
qp->Request(args[1].addr, funresult);
|
|
|
|
bool found=false;
|
|
if (((Attribute*)funresult.addr)->IsDefined())
|
|
{
|
|
found = ((CcBool*)funresult.addr)->GetBoolval();
|
|
}
|
|
|
|
// check if the tuple needs to be passed over
|
|
if (found)
|
|
{
|
|
if ( !ri->passOver() )
|
|
tuple->DeleteIfAllowed();
|
|
else
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (tuple)
|
|
{
|
|
result.addr = tuple;
|
|
return YIELD;
|
|
}
|
|
else
|
|
{
|
|
return CANCEL;
|
|
}
|
|
}
|
|
|
|
case CLOSE:
|
|
|
|
qp->Close(args[0].addr);
|
|
if(local.addr){
|
|
delete ri;
|
|
local.setAddr(0);
|
|
}
|
|
return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
5.9.3 Specification of operator ~project~
|
|
|
|
*/
|
|
const string ProjectSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
|
"\"Example\" ) "
|
|
"( <text>((stream (tuple ((x1 T1) ... "
|
|
"(xn Tn)))) (ai1 ... aik)) -> (stream (tuple"
|
|
" ((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--->"
|
|
") )";
|
|
|
|
/*
|
|
5.9.4 Definition of operator ~project~
|
|
|
|
*/
|
|
#ifndef USE_PROGRESS
|
|
Operator relalgproject (
|
|
"project", // name
|
|
ProjectSpec, // specification
|
|
OperatorProject::Project, // value mapping
|
|
Operator::SimpleSelect, // trivial selection function
|
|
OperatorProject::ProjectTypeMap // type mapping
|
|
);
|
|
#else
|
|
Operator relalgproject (
|
|
"project", // name
|
|
ProjectSpec, // specification
|
|
OperatorProject::Project, // value mapping
|
|
Operator::SimpleSelect, // trivial selection function
|
|
OperatorProject::ProjectTypeMap, // type mapping
|
|
OperatorProject::ProjectCostEstimationFunc // cost estimation
|
|
);
|
|
#endif
|
|
|
|
/*
|
|
2.5 Operator ~remove~
|
|
|
|
2.5.1 Type mapping function of operator ~remove~
|
|
|
|
Result type of ~remove~ operation.
|
|
|
|
---- ((stream (tuple ((x1 T1) ... (xn Tn)))) (ai1 ... aik)) ->
|
|
|
|
(APPEND
|
|
(n-k (j1 ... jn-k))
|
|
(stream (tuple ((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 RemoveTypeMap(ListExpr args)
|
|
{
|
|
bool firstcall = true;
|
|
int noAttrs=0, j=0;
|
|
|
|
// initialize all ListExpr with the empty list
|
|
ListExpr first = nl->TheEmptyList();
|
|
ListExpr second = first,
|
|
first2 = first,
|
|
attrtype = first,
|
|
newAttrList = first,
|
|
lastNewAttrList = first,
|
|
lastNumberList = first,
|
|
numberList = first,
|
|
outlist = first;
|
|
|
|
string attrname="", argstr="";
|
|
set<int> removeSet;
|
|
removeSet.clear();
|
|
|
|
if(nl->ListLength(args)!=2){
|
|
ErrorReporter::ReportError("tuple stream x attrlist expected");
|
|
return nl->TypeError();
|
|
}
|
|
|
|
first = nl->First(args);
|
|
second = nl->Second(args);
|
|
|
|
if(!listutils::isTupleStream(first)){
|
|
ErrorReporter::ReportError("first argument is not a tuple stream");
|
|
return nl->TypeError();
|
|
}
|
|
|
|
if(nl->ListLength(second)<=0){
|
|
ErrorReporter::ReportError("non empty attr list "
|
|
"expected as second argumnet");
|
|
return nl->TypeError();
|
|
}
|
|
|
|
|
|
while (!(nl->IsEmpty(second)))
|
|
{
|
|
first2 = nl->First(second);
|
|
second = nl->Rest(second);
|
|
nl->WriteToString(argstr, first2);
|
|
if (nl->AtomType(first2) == SymbolType)
|
|
{
|
|
attrname = nl->SymbolValue(first2);
|
|
}
|
|
else
|
|
{
|
|
nl->WriteToString(argstr, first2);
|
|
ErrorReporter::ReportError("Operator remove gets '" + argstr +
|
|
"' as attributename.\n"
|
|
"Atrribute name may not be the name of a Secondo object!");
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
|
}
|
|
|
|
j = listutils::findAttribute(nl->Second(nl->Second(first)),
|
|
attrname, attrtype);
|
|
if (j) removeSet.insert(j);
|
|
else
|
|
{
|
|
nl->WriteToString( argstr, nl->Second(nl->Second(first)) );
|
|
ErrorReporter::ReportError(
|
|
"Attributename '" + attrname + "' is not known.\n"
|
|
"Known Attribute(s): " + argstr);
|
|
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 =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));
|
|
}
|
|
}
|
|
}
|
|
|
|
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(Tuple::BasicType()),
|
|
newAttrList)));
|
|
return outlist;
|
|
}
|
|
else
|
|
{
|
|
ErrorReporter::ReportError("Do not remove all attributes!");
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
|
}
|
|
}
|
|
|
|
/*
|
|
2.5.2 Value mapping function of operator ~remove~
|
|
|
|
The value mapping is the same as for project. The difference is treated in the type mapping.
|
|
|
|
|
|
|
|
2.5.3 Specification of operator ~remove~
|
|
|
|
*/
|
|
const string RemoveSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
|
"\"Example\" ) "
|
|
"( <text>((stream (tuple ((x1 T1) ... "
|
|
"(xn Tn)))) (ai1 ... aik)) -> (stream "
|
|
"(tuple ((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--->"
|
|
") )";
|
|
|
|
/*
|
|
2.5.4 Definition of operator ~remove~
|
|
|
|
*/
|
|
#ifndef USE_PROGRESS
|
|
Operator relalgremove (
|
|
"remove", // name
|
|
RemoveSpec, // specification
|
|
OperatorProject::Project,// value mapping
|
|
Operator::SimpleSelect, // trivial selection function
|
|
RemoveTypeMap // type mapping
|
|
);
|
|
#else
|
|
Operator relalgremove (
|
|
"remove", // name
|
|
RemoveSpec, // specification
|
|
OperatorProject::Project, // value mapping
|
|
Operator::SimpleSelect, // trivial selection function
|
|
RemoveTypeMap, // type mapping
|
|
OperatorProject::ProjectCostEstimationFunc // cost estimation
|
|
);
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
5.10 Operator ~product~
|
|
|
|
5.10.1 Type mapping function of operator ~product~
|
|
|
|
Result type of product operation.
|
|
|
|
---- ((stream (tuple (x1 ... xn))) (stream (tuple (y1 ... ym))))
|
|
-> (stream (tuple (x1 ... xn y1 ... ym)))
|
|
----
|
|
|
|
The right argument stream will be materialized.
|
|
|
|
*/
|
|
ListExpr ProductTypeMap(ListExpr args)
|
|
{
|
|
if(nl->ListLength(args)!=2){
|
|
ErrorReporter::ReportError("tweo arguments expected");
|
|
return nl->TypeError();
|
|
}
|
|
ListExpr first = nl->First(args);
|
|
ListExpr second = nl->Second(args);
|
|
|
|
if(!listutils::isTupleStream(first) ||
|
|
!listutils::isTupleStream(second)){
|
|
ErrorReporter::ReportError(" stream(tuple(...)) x "
|
|
"stream(tuple(...)) expected");
|
|
return nl->TypeError();
|
|
}
|
|
|
|
ListExpr list1 = nl->Second(nl->Second(first));
|
|
ListExpr list2 = nl->Second(nl->Second(second));
|
|
|
|
ListExpr list = ConcatLists(list1, list2);
|
|
|
|
if(!listutils::isAttrList(list)){
|
|
ErrorReporter::ReportError("name conflict in concatenated tuples");
|
|
return nl->TypeError();
|
|
}
|
|
ListExpr outlist = nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()),
|
|
nl->TwoElemList(
|
|
nl->SymbolAtom(Tuple::BasicType()),list));
|
|
return outlist;
|
|
}
|
|
|
|
/*
|
|
5.10.2 Value mapping function of operator ~product~
|
|
|
|
*/
|
|
|
|
#ifndef USE_PROGRESS
|
|
|
|
// standard version
|
|
|
|
|
|
struct ProductLocalInfo
|
|
{
|
|
TupleType *resultTupleType;
|
|
Tuple* currentTuple;
|
|
TupleBuffer *rightRel;
|
|
GenericRelationIterator *iter;
|
|
};
|
|
|
|
int
|
|
Product(Word* args, Word& result, int message,
|
|
Word& local, Supplier s)
|
|
{
|
|
Word r, u;
|
|
ProductLocalInfo* pli;
|
|
TupleType* tt = (TupleType*) qp->GetLocal2(s).addr;
|
|
|
|
switch (message)
|
|
{
|
|
case INIT : {
|
|
tt = new TupleType(nl->Second(GetTupleResultType(s)));
|
|
qp->GetLocal2(s).addr = tt;
|
|
return 0;
|
|
}
|
|
case FINISH : {
|
|
if(tt){
|
|
tt->DeleteIfAllowed();
|
|
qp->GetLocal2(s).addr=0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
case OPEN :
|
|
{
|
|
|
|
long MAX_MEMORY = (qp->GetMemorySize(s) * 1024 * 1024);
|
|
cmsg.info("RA:ShowMemInfo")
|
|
<< "Product.MAX_MEMORY ("
|
|
<< MAX_MEMORY/1024 << " MB): " << endl;
|
|
cmsg.send();
|
|
|
|
qp->Open(args[0].addr);
|
|
qp->Request(args[0].addr, r);
|
|
pli = new ProductLocalInfo;
|
|
pli->currentTuple =
|
|
qp->Received(args[0].addr) ? (Tuple*)r.addr : 0;
|
|
|
|
/* materialize right stream */
|
|
qp->Open(args[1].addr);
|
|
qp->Request(args[1].addr, u);
|
|
|
|
if(qp->Received(args[1].addr))
|
|
{
|
|
pli->rightRel = new TupleBuffer( MAX_MEMORY );
|
|
}
|
|
else
|
|
{
|
|
pli->rightRel = 0;
|
|
}
|
|
|
|
while(qp->Received(args[1].addr))
|
|
{
|
|
Tuple *t = (Tuple*)u.addr;
|
|
pli->rightRel->AppendTuple( t );
|
|
t->DeleteIfAllowed();
|
|
qp->Request(args[1].addr, u);
|
|
}
|
|
|
|
if( pli->rightRel )
|
|
{
|
|
pli->iter = pli->rightRel->MakeScan();
|
|
}
|
|
else
|
|
{
|
|
pli->iter = 0;
|
|
}
|
|
|
|
tt->IncReference();
|
|
pli->resultTupleType = tt;
|
|
|
|
local.setAddr(pli);
|
|
return 0;
|
|
}
|
|
case REQUEST :
|
|
{
|
|
Tuple *resultTuple, *rightTuple;
|
|
pli = (ProductLocalInfo*)local.addr;
|
|
|
|
if (pli->currentTuple == 0)
|
|
{
|
|
return CANCEL;
|
|
}
|
|
else
|
|
{
|
|
if( pli->rightRel == 0 ) // second stream is empty
|
|
{
|
|
return CANCEL;
|
|
}
|
|
else if( (rightTuple = pli->iter->GetNextTuple()) != 0 )
|
|
{
|
|
resultTuple = new Tuple( pli->resultTupleType );
|
|
Concat(pli->currentTuple, rightTuple, resultTuple);
|
|
rightTuple->DeleteIfAllowed();
|
|
result.setAddr(resultTuple);
|
|
return YIELD;
|
|
}
|
|
else
|
|
{
|
|
/* restart iterator for right relation and
|
|
fetch a new tuple from left stream */
|
|
pli->currentTuple->DeleteIfAllowed();
|
|
pli->currentTuple = 0;
|
|
delete pli->iter;
|
|
pli->iter = 0;
|
|
qp->Request(args[0].addr, r);
|
|
if (qp->Received(args[0].addr))
|
|
{
|
|
pli->currentTuple = (Tuple*)r.addr;
|
|
pli->iter = pli->rightRel->MakeScan();
|
|
rightTuple = pli->iter->GetNextTuple();
|
|
assert( rightTuple != 0 );
|
|
resultTuple = new Tuple( pli->resultTupleType );
|
|
Concat(pli->currentTuple, rightTuple, resultTuple);
|
|
rightTuple->DeleteIfAllowed();
|
|
result.setAddr(resultTuple);
|
|
return YIELD;
|
|
}
|
|
else
|
|
{
|
|
return CANCEL; // left stream exhausted
|
|
}
|
|
}
|
|
}
|
|
}
|
|
case CLOSE :
|
|
{
|
|
pli = (ProductLocalInfo*)local.addr;
|
|
if(pli)
|
|
{
|
|
if(pli->currentTuple != 0)
|
|
pli->currentTuple->DeleteIfAllowed();
|
|
if( pli->iter != 0 )
|
|
delete pli->iter;
|
|
pli->resultTupleType->DeleteIfAllowed();
|
|
if( pli->rightRel )
|
|
{
|
|
pli->rightRel->Clear();
|
|
delete pli->rightRel;
|
|
}
|
|
delete pli;
|
|
local.setAddr(0);
|
|
}
|
|
|
|
qp->Close(args[0].addr);
|
|
qp->Close(args[1].addr);
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
# else
|
|
|
|
// progress version
|
|
|
|
CostEstimation* ProductCostEstimatonFunc()
|
|
{
|
|
return new ProductCostEstimation();
|
|
}
|
|
|
|
int
|
|
Product(Word* args, Word& result, int message,
|
|
Word& local, Supplier s)
|
|
{
|
|
Word r, u;
|
|
ProductLocalInfo* pli;
|
|
|
|
pli = (ProductLocalInfo*)local.addr;
|
|
TupleType* tt = (TupleType*) qp->GetLocal2(s).addr;
|
|
|
|
switch (message)
|
|
{
|
|
case INIT: {
|
|
tt = new TupleType(nl->Second(GetTupleResultType(s)));
|
|
qp->GetLocal2(s).addr = tt;
|
|
return 0;
|
|
}
|
|
|
|
case FINISH: {
|
|
if(tt){
|
|
tt->DeleteIfAllowed();
|
|
qp->GetLocal2(s).addr=0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
case OPEN:
|
|
{
|
|
long MAX_MEMORY = (qp->GetMemorySize(s) * 1024 * 1024); // in bytes
|
|
cmsg.info("RA:ShowMemInfo")
|
|
<< "Product.MAX_MEMORY ("
|
|
<< MAX_MEMORY/1024 << " kB): " << endl;
|
|
cmsg.send();
|
|
|
|
if ( pli ) delete pli;
|
|
pli = new ProductLocalInfo;
|
|
|
|
qp->Open(args[0].addr);
|
|
qp->Request(args[0].addr, r);
|
|
|
|
pli->currentTuple =
|
|
qp->Received(args[0].addr) ? (Tuple*)r.addr : 0;
|
|
|
|
/* materialize right stream */
|
|
qp->Open(args[1].addr);
|
|
qp->Request(args[1].addr, u);
|
|
|
|
if(qp->Received(args[1].addr))
|
|
{
|
|
pli->rightRel = new TupleBuffer( MAX_MEMORY );
|
|
}
|
|
else
|
|
{
|
|
pli->rightRel = 0;
|
|
}
|
|
|
|
pli->readSecond = 0;
|
|
pli->returned = 0;
|
|
local.setAddr(pli);
|
|
|
|
while(qp->Received(args[1].addr))
|
|
{
|
|
Tuple *t = (Tuple*)u.addr;
|
|
pli->rightRel->AppendTuple( t );
|
|
t->DeleteIfAllowed();
|
|
qp->Request(args[1].addr, u);
|
|
pli->readSecond++;
|
|
}
|
|
if( pli->rightRel )
|
|
{
|
|
pli->iter = pli->rightRel->MakeScan();
|
|
}
|
|
else
|
|
{
|
|
pli->iter = 0;
|
|
}
|
|
tt->IncReference();
|
|
pli->resultTupleType = tt;
|
|
|
|
return 0;
|
|
}
|
|
|
|
case REQUEST:
|
|
{
|
|
Tuple *resultTuple, *rightTuple;
|
|
|
|
if (pli->currentTuple == 0)
|
|
{
|
|
return CANCEL;
|
|
}
|
|
else
|
|
{
|
|
if( pli->rightRel == 0 ) // second stream is empty
|
|
{
|
|
return CANCEL;
|
|
}
|
|
else if( (rightTuple = pli->iter->GetNextTuple()) != 0 )
|
|
{
|
|
resultTuple = new Tuple( pli->resultTupleType );
|
|
Concat(pli->currentTuple, rightTuple, resultTuple);
|
|
rightTuple->DeleteIfAllowed();
|
|
result.setAddr(resultTuple);
|
|
pli->returned++;
|
|
return YIELD;
|
|
}
|
|
else
|
|
{
|
|
/* restart iterator for right relation and
|
|
fetch a new tuple from left stream */
|
|
pli->currentTuple->DeleteIfAllowed();
|
|
pli->currentTuple = 0;
|
|
delete pli->iter;
|
|
pli->iter = 0;
|
|
qp->Request(args[0].addr, r);
|
|
if (qp->Received(args[0].addr))
|
|
{
|
|
pli->currentTuple = (Tuple*)r.addr;
|
|
pli->iter = pli->rightRel->MakeScan();
|
|
rightTuple = pli->iter->GetNextTuple();
|
|
assert( rightTuple != 0 );
|
|
resultTuple = new Tuple( pli->resultTupleType );
|
|
Concat(pli->currentTuple, rightTuple, resultTuple);
|
|
rightTuple->DeleteIfAllowed();
|
|
result.setAddr(resultTuple);
|
|
pli->returned++;
|
|
return YIELD;
|
|
}
|
|
else
|
|
{
|
|
return CANCEL; // left stream exhausted
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
case CLOSE:
|
|
{
|
|
// Note: object deletion is done in (repeated) OPEN and CLOSEPROGRESS
|
|
qp->Close(args[0].addr);
|
|
qp->Close(args[1].addr);
|
|
|
|
if ( pli ){
|
|
delete pli;
|
|
local.setAddr(0);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
/*
|
|
5.10.3 Specification of operator ~product~
|
|
|
|
*/
|
|
const string ProductSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
|
"\"Example\" \"Remark\" ) "
|
|
"( <text>((stream (tuple (x1 ... xn))) (stream "
|
|
"(tuple (y1 ... ym)))) -> (stream (tuple (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--->"
|
|
"<text>The right argument stream (2nd argument) "
|
|
"will be materialized.</text--->"
|
|
" ) )";
|
|
|
|
/*
|
|
5.10.4 Definition of operator ~product~
|
|
|
|
*/
|
|
#ifndef USE_PROGRESS
|
|
Operator relalgproduct (
|
|
"product", // name
|
|
ProductSpec, // specification
|
|
Product, // value mapping
|
|
Operator::SimpleSelect, // trivial selection function
|
|
ProductTypeMap // type mapping
|
|
// true // needs large amounts of memory
|
|
);
|
|
#else
|
|
Operator relalgproduct (
|
|
"product", // name
|
|
ProductSpec, // specification
|
|
Product, // value mapping
|
|
Operator::SimpleSelect, // trivial selection function
|
|
ProductTypeMap, // type mapping
|
|
ProductCostEstimatonFunc // cost estimation
|
|
// true // needs large amounts of memory
|
|
);
|
|
#endif
|
|
|
|
/*
|
|
5.11 Operator ~count~
|
|
|
|
Count the number of tuples within a stream of tuples.
|
|
|
|
5.11.1 Type mapping function of operator ~count~
|
|
|
|
Operator ~count~ accepts a stream of tuples and returns an integer.
|
|
|
|
---- (stream (tuple x)) -> int
|
|
----
|
|
|
|
*/
|
|
ListExpr
|
|
TCountTypeMap(ListExpr args)
|
|
{
|
|
|
|
if(nl->ListLength(args)!=1){
|
|
ErrorReporter::ReportError("one argument expected");
|
|
return nl->TypeError();
|
|
}
|
|
ListExpr arg = nl->First(args);
|
|
if(!listutils::isRelDescription(arg,true) &&
|
|
!listutils::isRelDescription(arg,false) &&
|
|
!listutils::isOrelDescription(arg) &&
|
|
!listutils::isTupleStream(arg)){
|
|
ErrorReporter::ReportError( "rel(tuple(...)), orel(tuple(...),(...)), "
|
|
" (trel(tuple(...))"
|
|
" or stream(tuple(...)) expected");
|
|
return nl->TypeError();
|
|
}
|
|
return nl->SymbolAtom(CcInt::BasicType());
|
|
}
|
|
|
|
|
|
struct CountBothInfo : OperatorInfo {
|
|
|
|
CountBothInfo() : OperatorInfo()
|
|
{
|
|
name = "countboth";
|
|
signature = "stream(tuple(y)) x stream(tuple(z)) -> int";
|
|
syntax = "_ _ countboth";
|
|
meaning = "Counts the number of tuples of two input streams. "
|
|
"The streams are requested alternately. The purpose of "
|
|
"this operator is to expose the overhead of the seek time.";
|
|
example = "plz feed orte feed countboth";
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
ListExpr
|
|
countboth_tm(ListExpr args)
|
|
{
|
|
if(nl->ListLength(args)!=2){
|
|
ErrorReporter::ReportError("two arguments expected");
|
|
return nl->TypeError();
|
|
}
|
|
|
|
if(!listutils::isTupleStream(nl->First(args)) ||
|
|
!listutils::isTupleStream(nl->Second(args))){
|
|
ErrorReporter::ReportError(" two tuple stream expected");
|
|
return nl->TypeError();
|
|
}
|
|
|
|
return nl->SymbolAtom(CcInt::BasicType());
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
5.11.2 Value mapping functions of operator ~count~
|
|
|
|
*/
|
|
|
|
int TCountStream(Word* args, Word& result, int message,
|
|
Word& local, Supplier s)
|
|
{
|
|
Word elem;
|
|
int count = 0;
|
|
|
|
//cout << "TCountStream called" << endl;
|
|
|
|
// ignore old progress messages
|
|
if ( message <= CLOSE )
|
|
{
|
|
qp->Open(args[0].addr);
|
|
qp->Request(args[0].addr, elem);
|
|
while ( qp->Received(args[0].addr) )
|
|
{
|
|
((Tuple*)elem.addr)->DeleteIfAllowed();
|
|
qp->Request(args[0].addr, elem);
|
|
count++;
|
|
}
|
|
result = qp->ResultStorage(s);
|
|
((CcInt*) result.addr)->Set(true, count);
|
|
qp->Close(args[0].addr);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int TCountRel(Word* args, Word& result, int message,
|
|
Word& local, Supplier s)
|
|
{
|
|
//cout << "TCountRel called" << endl;
|
|
|
|
// ignore old progress messages
|
|
if ( message <= CLOSE )
|
|
{
|
|
GenericRelation* rel = (GenericRelation*)args[0].addr;
|
|
result = qp->ResultStorage(s);
|
|
((CcInt*) result.addr)->Set(true, rel->GetNoTuples());
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#ifdef USE_PROGRESS
|
|
|
|
// progress version
|
|
CostEstimation* TcountStreamCostEstimationFunc()
|
|
{
|
|
return new TCountStreamCostEstimation();
|
|
}
|
|
|
|
CostEstimation* TcountRelCostEstimationFunc()
|
|
{
|
|
return new TCountRelCostEstimation();
|
|
}
|
|
|
|
|
|
int
|
|
countboth_vm( Word* args, Word& result, int message,
|
|
Word& local, Supplier s )
|
|
{
|
|
|
|
struct Counter
|
|
{
|
|
Counter() : count(0) {}
|
|
|
|
inline bool request(void* addr)
|
|
{
|
|
Word elem;
|
|
qp->Request(addr, elem);
|
|
bool ok = qp->Received(addr);
|
|
if (ok) {
|
|
count++;
|
|
static_cast<Tuple*>(elem.addr)->DeleteIfAllowed();
|
|
}
|
|
return ok;
|
|
}
|
|
|
|
int count;
|
|
|
|
};
|
|
|
|
qp->Open(args[0].addr);
|
|
qp->Open(args[1].addr);
|
|
|
|
Counter c;
|
|
|
|
bool recA = c.request(args[0].addr);
|
|
bool recB = c.request(args[1].addr);
|
|
|
|
while ( recA || recB )
|
|
{
|
|
if (recA) {
|
|
recA = c.request(args[0].addr);
|
|
}
|
|
if (recB) {
|
|
recB = c.request(args[1].addr);
|
|
}
|
|
}
|
|
result = qp->ResultStorage(s);
|
|
static_cast<CcInt*>(result.addr)->Set(true, c.count);
|
|
|
|
qp->Close(args[0].addr);
|
|
qp->Close(args[1].addr);
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
5.11.3 Value mapping function for operator ~count2~
|
|
|
|
This operator generates messages! Refer to "Messages.h".
|
|
|
|
*/
|
|
int
|
|
TCountStream2(Word* args, Word& result, int message,
|
|
Word& local, Supplier s)
|
|
{
|
|
Word elem;
|
|
int count = 0;
|
|
|
|
// Get a reference to the message center
|
|
static MessageCenter* msg = MessageCenter::GetInstance();
|
|
|
|
qp->Open(args[0].addr);
|
|
qp->Request(args[0].addr, elem);
|
|
while ( qp->Received(args[0].addr) )
|
|
{
|
|
if ((count % 100) == 0) {
|
|
// build a two elem list (simple count)
|
|
NList msgList( NList("simple"), NList(count) );
|
|
// send the message, the message center will call
|
|
// the registered handlers. Normally the client applications
|
|
// will register them.
|
|
ListExpr list = nl->TwoElemList(
|
|
nl->SymbolAtom("simple"),
|
|
nl->IntAtom(count));
|
|
msg->Send(nl,list);
|
|
}
|
|
((Tuple*)elem.addr)->DeleteIfAllowed();
|
|
qp->Request(args[0].addr, elem);
|
|
count++;
|
|
}
|
|
result = qp->ResultStorage(s);
|
|
((CcInt*) result.addr)->Set(true, count);
|
|
qp->Close(args[0].addr);
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
5.11.3 Specification of operator ~count~
|
|
|
|
*/
|
|
const string TCountSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
|
"\"Example\" ) "
|
|
"( <text>stream(tuple X) -> int, \n"
|
|
"rel(tuple(X) | orel(tuple(X) | trel(tuple(X) -> int"
|
|
"</text--->"
|
|
"<text>_ count</text--->"
|
|
"<text>Count number of tuples within a stream "
|
|
"or a relation (persistent, temporal, or ordered) of tuples.</text--->"
|
|
"<text>query cities count or query cities "
|
|
"feed count</text--->"
|
|
") )";
|
|
|
|
/*
|
|
5.11.4 Selection function of operator ~count~
|
|
|
|
*/
|
|
int
|
|
TCountSelect( ListExpr args ) {
|
|
return Stream<ANY>::checkType(nl->First(args))?0:1;
|
|
}
|
|
|
|
/*
|
|
|
|
5.11.5 Definition of operator ~count~
|
|
|
|
*/
|
|
ValueMapping countmap[] = {TCountStream, TCountRel };
|
|
|
|
#ifndef USE_PROGRESS
|
|
Operator relalgcount (
|
|
"count", // name
|
|
TCountSpec, // specification
|
|
2, // number of value mapping functions
|
|
countmap, // value mapping functions
|
|
TCountSelect, // selection function
|
|
TCountTypeMap // type mapping
|
|
);
|
|
#else
|
|
|
|
CreateCostEstimation createCostEstimationList[] = {
|
|
TcountStreamCostEstimationFunc, TcountRelCostEstimationFunc};
|
|
|
|
Operator relalgcount (
|
|
"count", // name
|
|
TCountSpec, // specification
|
|
2, // number of value mapping functions
|
|
countmap, // value mapping functions
|
|
TCountSelect, // selection function
|
|
TCountTypeMap, // type mapping
|
|
createCostEstimationList // cost estimation
|
|
);
|
|
|
|
#endif
|
|
|
|
|
|
const string TCountSpec2 =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
|
"\"Example\" ) "
|
|
"( '((stream (tuple x))) -> int'"
|
|
"'_ count2'"
|
|
"'Count number of tuples within a stream "
|
|
"or a relation of tuples. During computation messages are sent to the "
|
|
"client. The purpose of this operator is to demonstrate the "
|
|
"programming interfaces only.'"
|
|
"'query plz feed count2'"
|
|
") )";
|
|
|
|
Operator relalgcount2 (
|
|
"count2", // name
|
|
TCountSpec2, // specification
|
|
TCountStream2, // value mapping function
|
|
Operator::SimpleSelect,
|
|
TCountTypeMap // type mapping
|
|
);
|
|
/*
|
|
5.11 Operator ~roottuplesize~
|
|
|
|
Reports the size of the tuples' root part in a relation. This operator
|
|
is useful for the optimizer, but it is usable as an operator itself.
|
|
|
|
5.11.1 Type mapping function of operator ~roottuplesize~
|
|
|
|
Operator ~roottuplesize~ accepts a relation or a stream of tuples and
|
|
returns an integer.
|
|
|
|
---- (rel (tuple x)) -> int
|
|
(stream (tuple x)) -> int
|
|
----
|
|
|
|
*/
|
|
ListExpr
|
|
RootTupleSizeTypeMap(ListExpr args)
|
|
{
|
|
|
|
if(!nl->HasLength(args,1)){
|
|
return listutils::typeError("one argument expected");
|
|
}
|
|
ListExpr first = nl->First(args);
|
|
|
|
if(!listutils::isTupleStream(first) &&
|
|
!listutils::isRelDescription(first) &&
|
|
!Tuple::checkType(first)){
|
|
ErrorReporter::ReportError("tuple stream, relation, or tuple expected");
|
|
return nl->TypeError();
|
|
}
|
|
return nl->SymbolAtom(CcInt::BasicType());
|
|
}
|
|
|
|
/*
|
|
|
|
5.11.2 Value mapping functions of operator ~roottuplesize~
|
|
|
|
*/
|
|
int
|
|
RootTupleSizeStream(Word* args, Word& result, int message,
|
|
Word& local, Supplier s)
|
|
{
|
|
Word elem;
|
|
int count = 0;
|
|
double totalSize = 0;
|
|
|
|
qp->Open(args[0].addr);
|
|
qp->Request(args[0].addr, elem);
|
|
while ( qp->Received(args[0].addr) )
|
|
{
|
|
totalSize += ((Tuple*)elem.addr)->GetRootSize();
|
|
count++;
|
|
((Tuple*)elem.addr)->DeleteIfAllowed();
|
|
qp->Request(args[0].addr, elem);
|
|
}
|
|
result = qp->ResultStorage(s);
|
|
if(count > 0){
|
|
((CcInt*) result.addr)->Set( true, (int)(totalSize / count) );
|
|
} else {
|
|
((CcInt*) result.addr)->Set( false, 0 );
|
|
}
|
|
qp->Close(args[0].addr);
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
RootTupleSizeRel(Word* args, Word& result, int message,
|
|
Word& local, Supplier s)
|
|
{
|
|
Relation* rel = (Relation*)args[0].addr;
|
|
result = qp->ResultStorage(s);
|
|
long count = rel->GetNoTuples();
|
|
double totalsize = rel->GetTotalRootSize();
|
|
if(count > 0){
|
|
((CcInt*) result.addr)->Set(true, (int)(totalsize / count) );
|
|
} else {
|
|
((CcInt*) result.addr)->Set(false, 0 );
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
int
|
|
RootTupleSizeTuple(Word* args, Word& result, int message,
|
|
Word& local, Supplier s)
|
|
{
|
|
Tuple* tup = (Tuple*) args [0].addr;
|
|
result=qp->ResultStorage(s);
|
|
CcInt* res = (CcInt*) result.addr;
|
|
res->Set(true, tup->GetRootSize());
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
|
|
5.11.3 Specification of operator ~roottuplesize~
|
|
|
|
*/
|
|
const string RootTupleSizeSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
|
"\"Example\" ) "
|
|
"( <text>((stream|rel (tuple x))) | tuple -> int"
|
|
"</text--->"
|
|
"<text>_ roottuplesize</text--->"
|
|
"<text>Return the size of the tuples' root part within a "
|
|
"stream or a relation.</text--->"
|
|
"<text>query cities roottuplesize or query cities "
|
|
"feed roottuplesize</text--->"
|
|
") )";
|
|
|
|
/*
|
|
5.11.4 Selection function of operator ~roottuplesize~
|
|
|
|
*/
|
|
int roottuplesizeSelect(ListExpr args){
|
|
|
|
ListExpr arg = nl->First(args);
|
|
if(Stream<Tuple>::checkType(arg)){
|
|
return 0;
|
|
}
|
|
if(listutils::isRelDescription(arg)){
|
|
return 1;
|
|
}
|
|
if(Tuple::checkType(arg)){
|
|
return 2;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
5.11.5 Definition of operator ~roottuplesize~
|
|
|
|
*/
|
|
ValueMapping roottuplesizemap[] = {RootTupleSizeStream,
|
|
RootTupleSizeRel,
|
|
RootTupleSizeTuple };
|
|
|
|
Operator relalgroottuplesize (
|
|
"roottuplesize", // name
|
|
RootTupleSizeSpec, // specification
|
|
3, // number of value mapping functions
|
|
roottuplesizemap, // value mapping functions
|
|
roottuplesizeSelect, // selection function
|
|
RootTupleSizeTypeMap // type mapping
|
|
);
|
|
|
|
/*
|
|
5.11 Operator ~exttuplesize~
|
|
|
|
Reports the average size of the tuples in a relation taking into
|
|
account the extension part, i.e. the small FLOBs. This operator
|
|
is useful for the optimizer, but it is usable as an operator itself.
|
|
|
|
5.11.1 Type mapping function of operator ~exttuplesize~
|
|
|
|
Operator ~exttuplesize~ accepts a relation or a stream of tuples
|
|
and returns a real.
|
|
|
|
---- (rel (tuple x)) -> real
|
|
(stream (tuple x)) -> real
|
|
----
|
|
|
|
*/
|
|
ListExpr
|
|
ExtTupleSizeTypeMap(ListExpr args)
|
|
{
|
|
if(nl->ListLength(args)!=1){
|
|
ErrorReporter::ReportError("one argument expected");
|
|
return nl->TypeError();
|
|
}
|
|
ListExpr first = nl->First(args);
|
|
if(!listutils::isTupleStream(first) &&
|
|
!listutils::isRelDescription(first) &&
|
|
!Tuple::checkType(first)){
|
|
ErrorReporter::ReportError("tuple stream, relation, or tuple expected");
|
|
return nl->TypeError();
|
|
}
|
|
return nl->SymbolAtom(CcReal::BasicType());
|
|
}
|
|
|
|
/*
|
|
|
|
5.11.2 Value mapping functions of operator ~exttuplesize~
|
|
|
|
*/
|
|
int
|
|
ExtTupleSizeStream(Word* args, Word& result, int message,
|
|
Word& local, Supplier s)
|
|
{
|
|
Word elem;
|
|
int count = 0;
|
|
float size = 0;
|
|
|
|
qp->Open(args[0].addr);
|
|
qp->Request(args[0].addr, elem);
|
|
while ( qp->Received(args[0].addr) )
|
|
{
|
|
size += ((Tuple*)elem.addr)->GetExtSize();
|
|
count++;
|
|
((Tuple*)elem.addr)->DeleteIfAllowed();
|
|
qp->Request(args[0].addr, elem);
|
|
}
|
|
result = qp->ResultStorage(s);
|
|
if( count > 0 ){
|
|
((CcReal*) result.addr)->Set(true, (float)(size/count));
|
|
} else {
|
|
((CcReal*) result.addr)->Set(false, 0);
|
|
}
|
|
qp->Close(args[0].addr);
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
ExtTupleSizeRel(Word* args, Word& result, int message,
|
|
Word& local, Supplier s)
|
|
{
|
|
Relation* rel = (Relation*)args[0].addr;
|
|
result = qp->ResultStorage(s);
|
|
long count = rel->GetNoTuples();
|
|
double totalsize = rel->GetTotalExtSize();
|
|
if( count > 0 ){
|
|
((CcReal*) result.addr)->Set(true, (float)(totalsize/count));
|
|
} else {
|
|
((CcReal*) result.addr)->Set(false, 0.0);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
int
|
|
ExtTupleSizeTuple(Word* args, Word& result, int message,
|
|
Word& local, Supplier s)
|
|
{
|
|
Tuple* tup = (Tuple*) args [0].addr;
|
|
result=qp->ResultStorage(s);
|
|
CcReal* res = (CcReal*) result.addr;
|
|
res->Set(true, tup->GetExtSize());
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
|
|
5.11.3 Specification of operator ~exttuplesize~
|
|
|
|
*/
|
|
const string ExtTupleSizeSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
|
"\"Example\" ) "
|
|
"( <text>((stream/rel (tuple x))) | tuple -> real"
|
|
"</text--->"
|
|
"<text>_ exttuplesize</text--->"
|
|
"<text>Return the average size of the tuples within a stream "
|
|
"or a relation taking into account the small FLOBs.</text--->"
|
|
"<text>query cities exttuplesize or query cities "
|
|
"feed exttuplesize</text--->"
|
|
") )";
|
|
|
|
/*
|
|
5.11.4 Selection function of operator ~exttuplesize~
|
|
|
|
*/
|
|
|
|
int exttuplesizeSelect(ListExpr args){
|
|
|
|
ListExpr arg = nl->First(args);
|
|
if(Stream<Tuple>::checkType(arg)){
|
|
return 0;
|
|
}
|
|
if(listutils::isRelDescription(arg)){
|
|
return 1;
|
|
}
|
|
if(Tuple::checkType(arg)){
|
|
return 2;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
5.11.5 Definition of operator ~exttuplesize~
|
|
|
|
*/
|
|
ValueMapping exttuplesizemap[] = {ExtTupleSizeStream,
|
|
ExtTupleSizeRel,
|
|
ExtTupleSizeTuple };
|
|
|
|
Operator relalgexttuplesize (
|
|
"exttuplesize", // name
|
|
ExtTupleSizeSpec, // specification
|
|
3, // number of value mapping functions
|
|
exttuplesizemap, // value mapping functions
|
|
exttuplesizeSelect, // selection function
|
|
ExtTupleSizeTypeMap // type mapping
|
|
);
|
|
|
|
/*
|
|
5.11 Operator ~tuplesize~
|
|
|
|
Reports the average size of the tuples in a relation. This operator
|
|
is useful for the optimizer, but it is usable as an operator itself.
|
|
|
|
5.11.1 Type mapping function of operator ~tuplesize~
|
|
|
|
Operator ~tuplesize~ accepts a stream of tuples and returns a
|
|
real.
|
|
|
|
---- (rel (tuple x)) -> real
|
|
(stream (tuple x)) -> real
|
|
----
|
|
|
|
*/
|
|
ListExpr
|
|
TupleSizeTypeMap(ListExpr args)
|
|
{
|
|
if(nl->ListLength(args)!=1){
|
|
ErrorReporter::ReportError("one argument expected");
|
|
return nl->TypeError();
|
|
}
|
|
ListExpr first = nl->First(args);
|
|
if(!listutils::isTupleStream(first) &&
|
|
!listutils::isRelDescription(first,false) &&
|
|
!listutils::isRelDescription(first,true) &&
|
|
!Tuple::checkType(first)){
|
|
ErrorReporter::ReportError("tuple stream, relation, or tuple expected");
|
|
return nl->TypeError();
|
|
}
|
|
return nl->SymbolAtom(CcReal::BasicType());
|
|
}
|
|
|
|
/*
|
|
|
|
5.11.2 Value mapping functions of operator ~tuplesize~
|
|
|
|
*/
|
|
int
|
|
TupleSizeStream(Word* args, Word& result, int message,
|
|
Word& local, Supplier s)
|
|
{
|
|
Word elem;
|
|
int count = 0;
|
|
double size = 0;
|
|
|
|
qp->Open(args[0].addr);
|
|
qp->Request(args[0].addr, elem);
|
|
while ( qp->Received(args[0].addr) )
|
|
{
|
|
size += ((Tuple*)elem.addr)->GetSize();
|
|
count++;
|
|
((Tuple*)elem.addr)->DeleteIfAllowed();
|
|
qp->Request(args[0].addr, elem);
|
|
}
|
|
result = qp->ResultStorage(s);
|
|
|
|
if (count > 0){
|
|
((CcReal*) result.addr)->Set(true, (double)(size/count));
|
|
} else {
|
|
((CcReal*) result.addr)->Set(false, 0.0);
|
|
}
|
|
qp->Close(args[0].addr);
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
TupleSizeRel(Word* args, Word& result, int message,
|
|
Word& local, Supplier s)
|
|
{
|
|
Relation* rel = (Relation*)args[0].addr;
|
|
result = qp->ResultStorage(s);
|
|
long count = rel->GetNoTuples();
|
|
double totalsize = rel->GetTotalSize();
|
|
if(count > 0){
|
|
((CcReal*) result.addr)->Set(true, (double)(totalsize/count) );
|
|
} else {
|
|
((CcReal*) result.addr)->Set(false, 0.0);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
int
|
|
TupleSizeTuple(Word* args, Word& result, int message,
|
|
Word& local, Supplier s)
|
|
{
|
|
Tuple* tup = (Tuple*) args [0].addr;
|
|
result=qp->ResultStorage(s);
|
|
CcReal* res = (CcReal*) result.addr;
|
|
res->Set(true, tup->GetSize());
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
|
|
5.11.3 Specification of operator ~tuplesize~
|
|
|
|
*/
|
|
const string TupleSizeSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
|
"\"Example\" ) "
|
|
"( <text>((stream/rel (tuple x))) | tuple -> real"
|
|
"</text--->"
|
|
"<text>_ tuplesize</text--->"
|
|
"<text>Return the average size of the tuples within a stream "
|
|
"or a relation taking into account the FLOBs.</text--->"
|
|
"<text>query cities tuplesize or query cities "
|
|
"feed tuplesize</text--->"
|
|
") )";
|
|
|
|
/*
|
|
5.11.4 Selection function of operator ~tuplesize~
|
|
|
|
*/
|
|
|
|
int tuplesizeSelect(ListExpr args){
|
|
|
|
ListExpr arg = nl->First(args);
|
|
if(Stream<Tuple>::checkType(arg)){
|
|
return 0;
|
|
}
|
|
if(listutils::isRelDescription(arg)){
|
|
return 1;
|
|
}
|
|
if(Tuple::checkType(arg)){
|
|
return 2;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
5.11.5 Definition of operator ~tuplesize~
|
|
|
|
*/
|
|
ValueMapping tuplesizemap[] = {TupleSizeStream, TupleSizeRel, TupleSizeTuple };
|
|
|
|
Operator relalgtuplesize (
|
|
"tuplesize", // name
|
|
TupleSizeSpec, // specification
|
|
3, // number of value mapping functions
|
|
tuplesizemap, // value mapping functions
|
|
tuplesizeSelect, // selection function
|
|
TupleSizeTypeMap // type mapping
|
|
);
|
|
|
|
/*
|
|
5.10 Opeartor tuplememsize
|
|
|
|
5.10.1 Signature
|
|
|
|
*/
|
|
ListExpr memtuplesizeTM(ListExpr args){
|
|
string err ="tuple expected";
|
|
if(!nl->HasLength(args,1)){
|
|
return listutils::typeError("one argument expected");
|
|
}
|
|
if(!Tuple::checkType(nl->First(args))){
|
|
return listutils::typeError(err);
|
|
}
|
|
return listutils::basicSymbol<CcInt>();
|
|
}
|
|
|
|
/*
|
|
5.10.2 Value Mapping
|
|
|
|
*/
|
|
|
|
int
|
|
memtuplesizeVM(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
|
|
Tuple* tup = (Tuple*) args [0].addr;
|
|
result=qp->ResultStorage(s);
|
|
CcInt* res = (CcInt*) result.addr;
|
|
res->Set(true, tup->GetMemSize());
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
5.10.3 Specification
|
|
|
|
*/
|
|
|
|
OperatorSpec memtuplesizeSpec(
|
|
"tuple -> int",
|
|
" _ memtuplesize",
|
|
"Returns the size of the memory usage of a tuple ",
|
|
" query strassen feed extend [MTS : . memtuplesize] consume");
|
|
|
|
/*
|
|
5.10.4 Operator instance
|
|
|
|
*/
|
|
Operator memtuplesize (
|
|
"memtuplesize",
|
|
memtuplesizeSpec.getStr(),
|
|
memtuplesizeVM,
|
|
Operator::SimpleSelect,
|
|
memtuplesizeTM
|
|
);
|
|
|
|
|
|
/*
|
|
5.10.3 MemAlltrSize
|
|
|
|
*/
|
|
|
|
ListExpr memattrsizeTM(ListExpr args){
|
|
string err = "DATA expected";
|
|
if(!nl->HasLength(args,1)){
|
|
return listutils::typeError(err);
|
|
}
|
|
if(!listutils::isDATA(nl->First(args))){
|
|
return listutils::typeError(err);
|
|
}
|
|
return listutils::basicSymbol<CcInt>();
|
|
}
|
|
|
|
|
|
int
|
|
memattrsizeVM(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
Attribute* arg = (Attribute*) args[0].addr;
|
|
result = qp->ResultStorage(s);
|
|
CcInt* res = (CcInt*) result.addr;
|
|
res->Set(true,arg->GetMemSize());
|
|
return 0;
|
|
}
|
|
|
|
|
|
OperatorSpec memattrsizeSpec(
|
|
"DATA -> int",
|
|
" _ memattrsize",
|
|
"Returns the size of the memory usage of an attribute",
|
|
" query thecenter memattrsize");
|
|
|
|
/*
|
|
5.10.4 Operator instance
|
|
|
|
*/
|
|
Operator memattrsize (
|
|
"memattrsize",
|
|
memattrsizeSpec.getStr(),
|
|
memattrsizeVM,
|
|
Operator::SimpleSelect,
|
|
memattrsizeTM
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
5.11 Operator ~rootattrsize~
|
|
|
|
Reports the size of the attribute's root part in a relation. This operator
|
|
is useful for the optimizer, but it is usable as an operator itself.
|
|
|
|
5.11.1 Type mapping function of operator ~rootattrsize~
|
|
|
|
Operator ~rootattrsize~ accepts a relation or a stream of tuples and
|
|
an attribute name identifier and returns an integer.
|
|
|
|
---- (rel (tuple X)) x ident -> int
|
|
(stream (tuple X)) x ident -> int
|
|
----
|
|
|
|
*/
|
|
ListExpr
|
|
RootAttrSizeTypeMap(ListExpr args)
|
|
{
|
|
|
|
if(nl->ListLength(args)!=2){
|
|
ErrorReporter::ReportError("two arguments expected");
|
|
return nl->TypeError();
|
|
}
|
|
|
|
ListExpr first = nl->First(args);
|
|
ListExpr second = nl->Second(args);
|
|
|
|
if(!listutils::isRelDescription(first) &&
|
|
!listutils::isTupleStream(first)){
|
|
ErrorReporter::ReportError("rel(tuple(...)) or stream(tuple(...))"
|
|
" x ident expected");
|
|
return nl->TypeError();
|
|
}
|
|
|
|
if(nl->AtomType(second)!=SymbolType){
|
|
ErrorReporter::ReportError("invalid attribut name as second arg");
|
|
return nl->TypeError();
|
|
}
|
|
string attrname = nl->SymbolValue(second);
|
|
ListExpr attrtype;
|
|
int j = listutils::findAttribute(nl->Second(nl->Second(first)),
|
|
attrname, attrtype);
|
|
if (!j)
|
|
{
|
|
ErrorReporter::ReportError(
|
|
"Operator rootattrsize: Attribute name '" + attrname +
|
|
"' is not a known attribute name in the attribute list.");
|
|
return nl->TypeError();
|
|
}
|
|
|
|
return
|
|
nl->ThreeElemList(
|
|
nl->SymbolAtom(Symbol::APPEND()),
|
|
nl->OneElemList(nl->IntAtom(j)),
|
|
nl->SymbolAtom(CcInt::BasicType()));
|
|
}
|
|
|
|
/*
|
|
|
|
5.11.2 Value mapping functions of operator ~rootattrsize~
|
|
|
|
*/
|
|
int
|
|
RootAttrSizeStream(Word* args, Word& result, int message,
|
|
Word& local, Supplier s)
|
|
{
|
|
Word elem;
|
|
int count = 0;
|
|
double totalSize = 0;
|
|
|
|
qp->Open(args[0].addr);
|
|
qp->Request(args[0].addr, elem);
|
|
int i = ((CcInt*)args[2].addr)->GetIntval() - 1;
|
|
while ( qp->Received(args[0].addr) )
|
|
{
|
|
totalSize += ((Tuple*)elem.addr)->GetRootSize(i);
|
|
count++;
|
|
((Tuple*)elem.addr)->DeleteIfAllowed();
|
|
qp->Request(args[0].addr, elem);
|
|
}
|
|
result = qp->ResultStorage(s);
|
|
if( count > 0 ){
|
|
((CcInt*) result.addr)->Set( true, (long)(totalSize / count) );
|
|
} else {
|
|
((CcInt*) result.addr)->Set( false, 0 );
|
|
}
|
|
qp->Close(args[0].addr);
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
RootAttrSizeRel(Word* args, Word& result, int message,
|
|
Word& local, Supplier s)
|
|
{
|
|
Relation* rel = (Relation*)args[0].addr;
|
|
result = qp->ResultStorage(s);
|
|
int i = ((CcInt*)args[2].addr)->GetIntval() - 1;
|
|
long count = rel->GetNoTuples();
|
|
double totalsize = rel->GetTotalRootSize(i);
|
|
if( count > 0 ){
|
|
((CcInt*) result.addr)->Set(true, (long)(totalsize/count) );
|
|
} else {
|
|
((CcInt*) result.addr)->Set(false, 0 );
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
|
|
5.11.3 Specification of operator ~rootattrsize~
|
|
|
|
*/
|
|
const string RootAttrSizeSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
|
"\"Example\" ) "
|
|
"( <text>stream|rel(tuple X) x ident -> int"
|
|
"</text--->"
|
|
"<text>_ rootattrsize[_]</text--->"
|
|
"<text>Return the size of the attributes' root part within a "
|
|
"stream or a relation.</text--->"
|
|
"<text>query cities rootattrsize[loc] or query cities "
|
|
"feed rootattrsize[loc]</text--->"
|
|
") )";
|
|
|
|
/*
|
|
5.11.4 Selection function of operator ~rootattrsize~
|
|
|
|
This function is the same as for the ~count~ operator.
|
|
|
|
5.11.5 Definition of operator ~rootattrsize~
|
|
|
|
*/
|
|
ValueMapping rootattrsizemap[] = {RootAttrSizeStream,
|
|
RootAttrSizeRel };
|
|
|
|
Operator relalgrootattrsize (
|
|
"rootattrsize", // name
|
|
RootAttrSizeSpec, // specification
|
|
2, // number of value mapping functions
|
|
rootattrsizemap, // value mapping functions
|
|
TCountSelect, // selection function
|
|
RootAttrSizeTypeMap // type mapping
|
|
);
|
|
|
|
/*
|
|
5.11 Operator ~extattrsize~
|
|
|
|
Reports the size of the attribute in a relation taking into account
|
|
the extended part, i.e. the small FLOBs. This operator
|
|
is useful for the optimizer, but it is usable as an operator itself.
|
|
|
|
5.11.1 Type mapping function of operator ~extattrsize~
|
|
|
|
Operator ~extattrsize~ accepts a relation or a stream of tuples and
|
|
an attribute name identifier and returns a real.
|
|
|
|
---- (rel (tuple X)) x ident -> real
|
|
(stream (tuple X)) x ident -> real
|
|
----
|
|
|
|
*/
|
|
ListExpr
|
|
ExtAttrSizeTypeMap(ListExpr args)
|
|
{
|
|
if(nl->ListLength(args)!=2){
|
|
ErrorReporter::ReportError("two arguments expected");
|
|
return nl->TypeError();
|
|
}
|
|
|
|
ListExpr first = nl->First(args);
|
|
ListExpr second = nl->Second(args);
|
|
|
|
if(!listutils::isRelDescription(first) &&
|
|
!listutils::isTupleStream(first)){
|
|
ErrorReporter::ReportError("rel(tuple(...)) or stream(tuple(...))"
|
|
" x ident expected");
|
|
return nl->TypeError();
|
|
}
|
|
|
|
if(nl->AtomType(second)!=SymbolType){
|
|
ErrorReporter::ReportError("invalid attribut name as second arg");
|
|
return nl->TypeError();
|
|
}
|
|
string attrname = nl->SymbolValue(second);
|
|
ListExpr attrtype;
|
|
int j = listutils::findAttribute(nl->Second(nl->Second(first)),
|
|
attrname, attrtype);
|
|
if (!j)
|
|
{
|
|
ErrorReporter::ReportError(
|
|
"Operator rootattrsize: Attribute name '" + attrname +
|
|
"' is not a known attribute name in the attribute list.");
|
|
return nl->TypeError();
|
|
}
|
|
|
|
return
|
|
nl->ThreeElemList(
|
|
nl->SymbolAtom(Symbol::APPEND()),
|
|
nl->OneElemList(nl->IntAtom(j)),
|
|
nl->SymbolAtom(CcReal::BasicType()));
|
|
}
|
|
|
|
/*
|
|
|
|
5.11.2 Value mapping functions of operator ~extattrsize~
|
|
|
|
*/
|
|
int
|
|
ExtAttrSizeStream(Word* args, Word& result, int message,
|
|
Word& local, Supplier s)
|
|
{
|
|
Word elem;
|
|
int count = 0;
|
|
double totalSize = 0;
|
|
|
|
qp->Open(args[0].addr);
|
|
qp->Request(args[0].addr, elem);
|
|
int i = ((CcInt*)args[2].addr)->GetIntval() - 1;
|
|
while ( qp->Received(args[0].addr) )
|
|
{
|
|
totalSize += ((Tuple*)elem.addr)->GetExtSize(i);
|
|
count++;
|
|
((Tuple*)elem.addr)->DeleteIfAllowed();
|
|
qp->Request(args[0].addr, elem);
|
|
}
|
|
result = qp->ResultStorage(s);
|
|
if( count > 0 ){
|
|
((CcReal*) result.addr)->Set( true, (double)(totalSize / count) );
|
|
} else {
|
|
((CcReal*) result.addr)->Set( false, 0.0 );
|
|
}
|
|
qp->Close(args[0].addr);
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
ExtAttrSizeRel(Word* args, Word& result, int message,
|
|
Word& local, Supplier s)
|
|
{
|
|
Relation* rel = (Relation*)args[0].addr;
|
|
result = qp->ResultStorage(s);
|
|
int i = ((CcInt*)args[2].addr)->GetIntval() - 1;
|
|
long count = rel->GetNoTuples();
|
|
double totalsize = rel->GetTotalExtSize(i);
|
|
if( count > 0 ){
|
|
((CcReal*) result.addr)->Set(true, (double)(totalsize / count) );
|
|
} else {
|
|
((CcReal*) result.addr)->Set(false, 0.0 );
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
|
|
5.11.3 Specification of operator ~extattrsize~
|
|
|
|
*/
|
|
const string ExtAttrSizeSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
|
"\"Example\" ) "
|
|
"( <text>stream|rel(tuple X) x ident -> real"
|
|
"</text--->"
|
|
"<text>_ extattrsize[_]</text--->"
|
|
"<text>Return the size of the attribute within a "
|
|
"stream or a relation taking into account the "
|
|
"small FLOBs.</text--->"
|
|
"<text>query cities extattrsize[loc] or query cities "
|
|
"feed extattrsize[loc]</text--->"
|
|
") )";
|
|
|
|
/*
|
|
5.11.4 Selection function of operator ~extattrsize~
|
|
|
|
This function is the same as for the ~count~ operator.
|
|
|
|
5.11.5 Definition of operator ~extattrsize~
|
|
|
|
*/
|
|
ValueMapping extattrsizemap[] = {ExtAttrSizeStream,
|
|
ExtAttrSizeRel };
|
|
|
|
Operator relalgextattrsize (
|
|
"extattrsize", // name
|
|
ExtAttrSizeSpec, // specification
|
|
2, // number of value mapping functions
|
|
extattrsizemap, // value mapping functions
|
|
TCountSelect, // selection function
|
|
ExtAttrSizeTypeMap // type mapping
|
|
);
|
|
|
|
/*
|
|
5.11 Operator ~attrsize~
|
|
|
|
Reports the size of the attribute in a relation taking into account
|
|
the FLOBs. This operator is useful for the optimizer, but it is
|
|
usable as an operator itself.
|
|
|
|
5.11.1 Type mapping function of operator ~attrsize~
|
|
|
|
Operator ~attrsize~ accepts a relation or a stream of tuples and
|
|
an attribute name identifier and returns a real.
|
|
|
|
---- (rel (tuple X)) x ident -> real
|
|
(stream (tuple X)) x ident -> real
|
|
----
|
|
|
|
*/
|
|
ListExpr
|
|
AttrSizeTypeMap(ListExpr args)
|
|
{
|
|
if(nl->ListLength(args)!=2){
|
|
ErrorReporter::ReportError("two arguments expected");
|
|
return nl->TypeError();
|
|
}
|
|
|
|
ListExpr first = nl->First(args);
|
|
ListExpr second = nl->Second(args);
|
|
|
|
if(!listutils::isRelDescription(first) &&
|
|
!listutils::isTupleStream(first)){
|
|
ErrorReporter::ReportError("rel(tuple(...)) or stream(tuple(...))"
|
|
" x ident expected");
|
|
return nl->TypeError();
|
|
}
|
|
|
|
if(nl->AtomType(second)!=SymbolType){
|
|
ErrorReporter::ReportError("invalid attribut name as second arg");
|
|
return nl->TypeError();
|
|
}
|
|
string attrname = nl->SymbolValue(second);
|
|
ListExpr attrtype;
|
|
int j = listutils::findAttribute(nl->Second(nl->Second(first)),
|
|
attrname, attrtype);
|
|
if (!j)
|
|
{
|
|
ErrorReporter::ReportError(
|
|
"Operator rootattrsize: Attribute name '" + attrname +
|
|
"' is not a known attribute name in the attribute list.");
|
|
return nl->TypeError();
|
|
}
|
|
|
|
return
|
|
nl->ThreeElemList(
|
|
nl->SymbolAtom(Symbol::APPEND()),
|
|
nl->OneElemList(nl->IntAtom(j)),
|
|
nl->SymbolAtom(CcReal::BasicType()));
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
5.11.2 Value mapping functions of operator ~attrsize~
|
|
|
|
*/
|
|
int
|
|
AttrSizeStream(Word* args, Word& result, int message,
|
|
Word& local, Supplier s)
|
|
{
|
|
Word elem;
|
|
int count = 0;
|
|
double totalSize = 0;
|
|
|
|
qp->Open(args[0].addr);
|
|
qp->Request(args[0].addr, elem);
|
|
int i = ((CcInt*)args[2].addr)->GetIntval() - 1;
|
|
while ( qp->Received(args[0].addr) )
|
|
{
|
|
totalSize += ((Tuple*)elem.addr)->GetSize(i);
|
|
count++;
|
|
((Tuple*)elem.addr)->DeleteIfAllowed();
|
|
qp->Request(args[0].addr, elem);
|
|
}
|
|
result = qp->ResultStorage(s);
|
|
if( count > 0){
|
|
((CcReal*) result.addr)->Set( true, (double)(totalSize / count) );
|
|
} else {
|
|
((CcReal*) result.addr)->Set( false, 0.0 );
|
|
}
|
|
qp->Close(args[0].addr);
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
AttrSizeRel(Word* args, Word& result, int message,
|
|
Word& local, Supplier s)
|
|
{
|
|
Relation* rel = (Relation*)args[0].addr;
|
|
result = qp->ResultStorage(s);
|
|
int i = ((CcInt*)args[2].addr)->GetIntval() - 1;
|
|
long count = rel->GetNoTuples();
|
|
double totalsize = rel->GetTotalSize(i);
|
|
if( count > 0 ){
|
|
((CcReal*) result.addr)->Set(true, (double)(totalsize / count) );
|
|
} else {
|
|
((CcReal*) result.addr)->Set(false, 0.0 );
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
|
|
5.11.3 Specification of operator ~attrsize~
|
|
|
|
*/
|
|
const string AttrSizeSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
|
"\"Example\" ) "
|
|
"( <text>stream|rel(tuple X) x ident -> real"
|
|
"</text--->"
|
|
"<text>_ attrsize[_]</text--->"
|
|
"<text>Return the size of the attribute within a "
|
|
"stream or a relation taking into account the "
|
|
"FLOBs.</text--->"
|
|
"<text>query cities attrsize[loc] or query cities "
|
|
"feed attrsize[loc]</text--->"
|
|
") )";
|
|
|
|
/*
|
|
5.11.4 Selection function of operator ~attrsize~
|
|
|
|
This function is the same as for the ~count~ operator.
|
|
|
|
5.11.5 Definition of operator ~attrsize~
|
|
|
|
*/
|
|
ValueMapping attrsizemap[] = {AttrSizeStream,
|
|
AttrSizeRel };
|
|
|
|
Operator relalgattrsize (
|
|
"attrsize", // name
|
|
AttrSizeSpec, // specification
|
|
2, // number of value mapping functions
|
|
attrsizemap, // value mapping functions
|
|
TCountSelect, // selection function
|
|
AttrSizeTypeMap // type mapping
|
|
);
|
|
|
|
|
|
/*
|
|
5.12 Operator ~sizecounters~
|
|
|
|
This operator maps
|
|
|
|
---- (stream (tuple X)) x string -> (stream (tuple X))
|
|
----
|
|
|
|
It sums up the sizes (Root, Extension, Flobs) of the tuples of a given input
|
|
stream. These values are stored as entries in the system table SEC\_COUNTERS
|
|
which can be queried afterwards.
|
|
|
|
5.12.0 Specification
|
|
|
|
*/
|
|
|
|
struct SizeCountersInfo : OperatorInfo {
|
|
|
|
SizeCountersInfo() : OperatorInfo()
|
|
{
|
|
name = "sizecounters";
|
|
signature = "stream(tuple(y)) x string -> stream(tuple(y))";
|
|
syntax = "_ sizecounters[ s ]";
|
|
meaning = "Sums up the size for the tuples root size, the extension "
|
|
"size and the flob size. The results will be stored in "
|
|
"counters which are named \n\n"
|
|
"- RA:RootSize_s\n"
|
|
"- RA:ExtSize_s (Root + Extension)\n"
|
|
"- RA:Size_s (Root + Extension + Flobs)\n"
|
|
"- RA:FlobSizeOnly_s\n"
|
|
"- RA:ExtSizeOnly_s\n";
|
|
example = "plz feed sizecounters[\"plz\"] count";
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
5.12.1 Type mapping
|
|
|
|
The type mapping uses the wrapper class ~NList~ which hides calls
|
|
to class NestedList. Moreover, there are some useful functions for
|
|
handling streams of tuples.
|
|
|
|
*/
|
|
|
|
static ListExpr sizecounters_tm(ListExpr args)
|
|
{
|
|
NList l(args);
|
|
|
|
const string opName = "sizecounters";
|
|
string err1 = opName + "expects (stream(tuple(...)) string)!";
|
|
//cout << opName << ": " << l << endl;
|
|
|
|
if ( !l.checkLength(2, err1) )
|
|
return l.typeError( err1 );
|
|
|
|
NList attrs;
|
|
if ( !l.first().checkStreamTuple( attrs ) )
|
|
return l.typeError(err1);
|
|
|
|
if ( !l.second().isSymbol(Symbols::STRING()) )
|
|
return l.typeError(err1);
|
|
|
|
return l.first().listExpr();
|
|
}
|
|
|
|
/*
|
|
|
|
5.12.1 Value mapping
|
|
|
|
*/
|
|
|
|
static int sizecounters_vm( Word* args, Word& result, int message,
|
|
Word& local, Supplier s)
|
|
{
|
|
// args[0]: stream(tuple(...))
|
|
// args[1]: string
|
|
|
|
struct Info {
|
|
|
|
long& rootSize;
|
|
long& extSize;
|
|
long& size;
|
|
long& extSizeOnly;
|
|
long& flobSizeOnly;
|
|
long& tuples;
|
|
|
|
Info(const string& s) :
|
|
rootSize(Counter::getRef("RA::RootSize_" + s)),
|
|
extSize(Counter::getRef("RA::ExtSize_" + s)),
|
|
size(Counter::getRef("RA::Size_" + s)),
|
|
extSizeOnly(Counter::getRef("RA::ExtSizeOnly_" + s)),
|
|
flobSizeOnly(Counter::getRef("RA::FlobSizeOnly_" + s)),
|
|
tuples(Counter::getRef("RA::Tuples_" + s))
|
|
{}
|
|
~Info()
|
|
{}
|
|
|
|
void computeSizes()
|
|
{
|
|
extSizeOnly = size - rootSize;
|
|
flobSizeOnly = size - extSize;
|
|
}
|
|
|
|
void addSizes(Tuple* t)
|
|
{
|
|
tuples++;
|
|
rootSize += t->GetRootSize();
|
|
extSize += t->GetExtSize();
|
|
size += t->GetSize();
|
|
}
|
|
|
|
};
|
|
|
|
Info* pi = static_cast<Info*>( local.addr );
|
|
void* stream = args[0].addr;
|
|
|
|
switch ( message )
|
|
{
|
|
|
|
case OPEN: {
|
|
|
|
qp->Open(stream);
|
|
local.addr = new Info( StdTypes::GetString(args[1]) );
|
|
return 0;
|
|
}
|
|
|
|
case REQUEST: {
|
|
|
|
Word elem;
|
|
qp->Request(stream, elem);
|
|
if ( qp->Received(stream) )
|
|
{
|
|
Tuple* t = static_cast<Tuple*>(elem.addr);
|
|
pi->addSizes(t);
|
|
result = elem;
|
|
return YIELD;
|
|
}
|
|
else
|
|
{
|
|
return CANCEL;
|
|
}
|
|
}
|
|
|
|
case CLOSE: {
|
|
if(pi)
|
|
{
|
|
pi->computeSizes();
|
|
delete pi;
|
|
local.setAddr(0);
|
|
}
|
|
qp->Close(stream);
|
|
return 0;
|
|
}
|
|
|
|
default: {
|
|
assert(false);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
5.13 Operator ~dumpstream~
|
|
|
|
This operator maps
|
|
|
|
---- (stream (tuple y)) x string -> (stream (tuple y))
|
|
----
|
|
|
|
It just passes the tuples streamupwards and dumps the tuple values into a file
|
|
which is specified by the 2nd parameter.
|
|
|
|
5.12.0 Specification
|
|
|
|
*/
|
|
|
|
struct DumpStreamInfo : OperatorInfo {
|
|
|
|
DumpStreamInfo() : OperatorInfo()
|
|
{
|
|
name = "dumpstream";
|
|
signature = "stream(tuple(y)) x string -> stream(tuple(y))";
|
|
syntax = "_ dumpstream[ f, s ]";
|
|
meaning = "Appends the tuples' values to a file specified by f. "
|
|
"The attribute values are separated by s.";
|
|
example = "plz feed dumpstream[\"plz.txt\", \"|\"] count";
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/*
|
|
5.12.1 Type mapping
|
|
|
|
The type mapping uses the wrapper class ~NList~ which hides calls
|
|
to class NestedList. Moreover, there are some useful functions for
|
|
handling streams of tuples.
|
|
|
|
(stream(tuple(x))) -> (APPEND (list of attr names) stream(tuple(x))
|
|
|
|
|
|
*/
|
|
|
|
static ListExpr dumpstream_tm(ListExpr args)
|
|
{
|
|
NList l(args);
|
|
|
|
const string opName = "dumpstream";
|
|
string err1 = opName + "expects (stream(tuple(...)) string string)!";
|
|
|
|
if ( !l.checkLength(3, err1) )
|
|
return l.typeError( err1 );
|
|
|
|
NList attrs;
|
|
if ( !l.first().checkStreamTuple( attrs ) )
|
|
return l.typeError(err1);
|
|
|
|
if ( !l.second().isSymbol(Symbols::STRING()) )
|
|
return l.typeError(err1);
|
|
|
|
if ( !l.third().isSymbol(Symbols::STRING()) )
|
|
return l.typeError(err1);
|
|
|
|
NList attrNames;
|
|
while ( !attrs.isEmpty() ) {
|
|
cout << attrs.first().first() << endl;
|
|
attrNames.append( attrs.first().first().toStringAtom() );
|
|
attrs.rest();
|
|
}
|
|
|
|
|
|
// the following line can be compiled using newer gcc compilers (4.1.x),
|
|
// to be compatible with older ones, this line is replaced by
|
|
// two lines.
|
|
// NList result( NList(Symbols::APPEND()), attrNames, l.first() );
|
|
NList tmp(Symbols::APPEND());
|
|
NList result(tmp,attrNames, l.first() );
|
|
|
|
|
|
|
|
return result.listExpr();
|
|
}
|
|
|
|
/*
|
|
|
|
5.12.1 Value mapping
|
|
|
|
*/
|
|
|
|
static int dumpstream_vm( Word* args, Word& result, int message,
|
|
Word& local, Supplier s)
|
|
{
|
|
// args[0]: stream(tuple(...))
|
|
// args[1]: string -> file name
|
|
// args[2]: string -> separator
|
|
|
|
struct Info {
|
|
|
|
ofstream os;
|
|
const string colsep;
|
|
int maxAttr;
|
|
int ctr;
|
|
|
|
Info(const string& fileName, const string& sep, int max) :
|
|
colsep(sep)
|
|
{
|
|
maxAttr = max;
|
|
ctr = 0;
|
|
os.open(fileName.c_str(), ios_base::app);
|
|
}
|
|
~Info()
|
|
{
|
|
os.close();
|
|
}
|
|
|
|
void appendTuple(Tuple& t)
|
|
{
|
|
for( int i = 0; i < t.GetNoAttributes(); i++)
|
|
{
|
|
os << *t.GetAttribute(i);
|
|
if (i < maxAttr - 1)
|
|
os << colsep;
|
|
else
|
|
os << endl;
|
|
}
|
|
}
|
|
|
|
void appendToHeadLine(Word w)
|
|
{
|
|
if (ctr == maxAttr)
|
|
return;
|
|
|
|
string attrStr = StdTypes::GetString( w );
|
|
//cerr << attrStr << endl;
|
|
os << attrStr;
|
|
if (ctr < maxAttr - 1)
|
|
os << colsep;
|
|
else
|
|
os << endl;
|
|
ctr++;
|
|
}
|
|
|
|
};
|
|
|
|
Info* pi = static_cast<Info*>( local.addr );
|
|
void* stream = args[0].addr;
|
|
|
|
switch ( message )
|
|
{
|
|
|
|
case OPEN: {
|
|
|
|
qp->Open(stream);
|
|
|
|
string name = StdTypes::GetString(args[1]);
|
|
string colsep = StdTypes::GetString(args[2]);
|
|
|
|
int max = qp->GetNoSons( s );
|
|
pi = new Info(name, colsep, max-3);
|
|
local.addr = pi;
|
|
|
|
for (int i=3; i < max; i++)
|
|
{
|
|
pi->appendToHeadLine( args[i] );
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
case REQUEST: {
|
|
|
|
Word elem;
|
|
qp->Request(stream, elem);
|
|
if ( qp->Received(stream) )
|
|
{
|
|
Tuple* t = static_cast<Tuple*>(elem.addr);
|
|
pi->appendTuple(*t);
|
|
result = elem;
|
|
return YIELD;
|
|
}
|
|
else
|
|
{
|
|
return CANCEL;
|
|
}
|
|
}
|
|
|
|
case CLOSE: {
|
|
if(pi)
|
|
{
|
|
delete pi;
|
|
local.setAddr(0);
|
|
}
|
|
qp->Close(stream);
|
|
return 0;
|
|
}
|
|
|
|
default: {
|
|
assert(false);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
5.12 Operator ~rename~
|
|
|
|
Renames all attribute names by adding them with the postfix passed
|
|
as parameter.
|
|
|
|
5.12.1 Type mapping function of operator ~rename~
|
|
|
|
Type mapping for ~rename~ is
|
|
|
|
---- ((stream (tuple([a1:d1, ... ,an:dn)))ar) ->
|
|
(stream (tuple([a1ar:d1, ... ,anar:dn)))
|
|
----
|
|
|
|
*/
|
|
|
|
ListExpr
|
|
RenameTypeMap( ListExpr args )
|
|
{
|
|
ListExpr first=nl->TheEmptyList();
|
|
ListExpr first2=first, second=first, rest=first,
|
|
listn=first, lastlistn=first, tup, tupFirst, type;
|
|
string attrname="", argstr="";
|
|
string attrnamen="";
|
|
bool firstcall = true;
|
|
|
|
|
|
if(nl->ListLength(args)!=2){
|
|
return listutils::typeError("Operator rename expects "
|
|
"two arguments.");
|
|
}
|
|
|
|
first = nl->First(args);
|
|
second = nl->Second(args);
|
|
|
|
nl->WriteToString(argstr, first);
|
|
if (!IsStreamDescription(first)) {
|
|
ErrorReporter::ReportError(
|
|
"Operator rename expects a valid tuple stream "
|
|
"Operator rename gets a list with structure '" + argstr + "'.");
|
|
return nl->TypeError();
|
|
}
|
|
|
|
nl->WriteToString(argstr, second);
|
|
|
|
if(!listutils::isSymbol(second)){
|
|
return listutils::typeError("the second argument must be a symbol");
|
|
}
|
|
|
|
tup = nl->Second(nl->Second(first));
|
|
while (!(nl->IsEmpty(tup)))
|
|
{
|
|
tupFirst = nl->First(tup);
|
|
type = nl->Second(tupFirst);
|
|
if (!(nl->IsAtom(type)))
|
|
{
|
|
type = nl->First(type);
|
|
if (nl->IsAtom(type)&&(nl->SymbolValue(type) == "arel"))
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
|
}
|
|
tup = nl->Rest(tup);
|
|
}
|
|
|
|
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(Tuple::BasicType()),listn));
|
|
}
|
|
|
|
ListExpr RenameAttrTypeMap(ListExpr args){
|
|
|
|
|
|
if(nl->ListLength(args)!=2){
|
|
return listutils::typeError("Two arguments expected.");
|
|
}
|
|
|
|
ListExpr firstarg = nl->First(args);
|
|
if(nl->ListLength(firstarg) !=2){
|
|
return listutils::typeError("First argument must consists of 2 parts.");
|
|
}
|
|
|
|
ListExpr stream = nl->First(firstarg);
|
|
if(!listutils::isTupleStream(stream)){
|
|
return listutils::typeError("First argument must be a tuple stream.");
|
|
}
|
|
|
|
ListExpr secondarg = nl->Second(args);
|
|
if(nl->ListLength(secondarg) !=2){
|
|
return listutils::typeError("Second argument must consists of 2 parts.");
|
|
}
|
|
|
|
map<string,string> renameMap;
|
|
ListExpr renamesTypes = nl->First(secondarg); // get type list!
|
|
ListExpr renamesValues = nl->Second(secondarg); // get value list!
|
|
ListExpr attrList = nl->Second(nl->Second(stream));
|
|
|
|
if(nl->AtomType(renamesTypes)!=NoAtom){
|
|
return listutils::typeError("Second argument must be a list of renamings.");
|
|
}
|
|
if(nl->AtomType(renamesValues)!=NoAtom){
|
|
return listutils::typeError("Second argument must be a list of renamings.");
|
|
}
|
|
|
|
while(!nl->IsEmpty(renamesTypes) && !nl->IsEmpty(renamesValues)){
|
|
ListExpr renameType = nl->First(renamesTypes);
|
|
renamesTypes = nl->Rest(renamesTypes);
|
|
ListExpr renameValue = nl->First(renamesValues);
|
|
renamesValues = nl->Rest(renamesValues);
|
|
if(nl->ListLength(renameType)!=2){
|
|
return listutils::typeError("Each rename must consist of the "
|
|
"old and the new attribute name.");
|
|
}
|
|
if(nl->ListLength(renameValue)!=2){
|
|
return listutils::typeError("Each rename must consist of the "
|
|
"old and the new attribute name.");
|
|
}
|
|
// determine NewAttrName
|
|
string newname = "";
|
|
if(listutils::isSymbol(nl->First(renameType),CcString::BasicType())){
|
|
newname = nl->StringValue(nl->First(renameValue));
|
|
} else if(listutils::isSymbol(nl->First(renameType))) {
|
|
newname = nl->SymbolValue(nl->First(renameType));
|
|
}
|
|
// determine OldAttrName
|
|
string oldname = "";
|
|
if(listutils::isSymbol(nl->Second(renameType),CcString::BasicType())){
|
|
oldname = nl->StringValue(nl->Second(renameValue));
|
|
} else if(listutils::isSymbol(nl->Second(renameType))) {
|
|
oldname = nl->SymbolValue(nl->Second(renameType));
|
|
}
|
|
|
|
// check if new name is a usuable identifier
|
|
if( (oldname=="") || (newname=="") ){
|
|
return listutils::typeError("Empty attribute name detected!");
|
|
}
|
|
string errmsg;
|
|
if(!listutils::isValidAttributeName(nl->SymbolAtom(newname),errmsg)){
|
|
return listutils::typeError(errmsg);
|
|
}
|
|
|
|
if(renameMap.find(oldname)!=renameMap.end()){
|
|
return listutils::typeError( "Attribute name '"
|
|
+oldname+"' renamed twice.");
|
|
} else {
|
|
renameMap[oldname] = newname;
|
|
}
|
|
}
|
|
|
|
ListExpr resAttrList;
|
|
string errmsg;
|
|
if(!listutils::replaceAttributes(attrList, renameMap, resAttrList, errmsg)){
|
|
return listutils::typeError(errmsg);
|
|
}
|
|
return nl->TwoElemList( nl->SymbolAtom(Symbol::STREAM()),
|
|
nl->TwoElemList(nl->SymbolAtom(Tuple::BasicType()),
|
|
resAttrList));
|
|
}
|
|
|
|
/*
|
|
5.12.1 validateAttrNames
|
|
|
|
Changes the names attribute names of a tuple stream to start with an upper case.
|
|
If there are name conflicts resulting of this renaming, the names are extended by
|
|
a sequential number. It returns false, if the names does not start with an character
|
|
in a,...,z,A,...,Z.
|
|
|
|
*/
|
|
bool isValidSymbolChar(char f){
|
|
if(f>='A' && f <='Z'){
|
|
return true;
|
|
}
|
|
if(f>='a' && f <='z'){
|
|
return true;
|
|
}
|
|
if(f>='0' && f <='9'){
|
|
return true;
|
|
}
|
|
if(f=='_'){
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool validateName(string& name){
|
|
char f = name[0];
|
|
// start with small letter
|
|
if( f>='a' && f<='z') {
|
|
f = (f - 'a') + 'A';
|
|
name[0] = f;
|
|
}
|
|
if(f<'A' || f>'Z'){ // start with a wrong character
|
|
name = "A_"+name;
|
|
}
|
|
for(unsigned int i=1;i<name.size();i++){
|
|
f = name[i];
|
|
if(!isValidSymbolChar(f)){
|
|
f = '_';
|
|
name[i] = f;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
ListExpr validateAttrTM(ListExpr args){
|
|
string err = "tuple stream expected";
|
|
if(!nl->HasLength(args,1)){
|
|
return listutils::typeError(err);
|
|
}
|
|
ListExpr stream = nl->First(args);
|
|
if(!Stream<Tuple>::checkType(stream)){
|
|
return listutils::typeError(err);
|
|
}
|
|
// start building the result
|
|
ListExpr res = nl->TheEmptyList();
|
|
ListExpr last = nl->TheEmptyList();
|
|
bool firstElem = true;
|
|
ListExpr attrList = nl->Second(nl->Second(stream));
|
|
|
|
set<string> usedNames;
|
|
|
|
|
|
while(!nl->IsEmpty(attrList)){
|
|
ListExpr first = nl->First(attrList);
|
|
attrList = nl->Rest(attrList);
|
|
string name = nl->SymbolValue(nl->First(first));
|
|
if(!validateName(name)){
|
|
return listutils::typeError("Attribute name found "
|
|
"which not starts with a character");
|
|
}
|
|
if(usedNames.find(name)!=usedNames.end()){
|
|
string basic = name + "_";
|
|
int num = 0;
|
|
do{
|
|
name = basic + stringutils::int2str(num);
|
|
num++;
|
|
} while(usedNames.find(name)!=usedNames.end());
|
|
}
|
|
// now, we have a unique name
|
|
ListExpr at = nl->TwoElemList(nl->SymbolAtom(name), nl->Second(first));
|
|
if(firstElem){
|
|
res = nl->OneElemList(at);
|
|
last = res;
|
|
firstElem=false;
|
|
} else {
|
|
last = nl->Append(last,at);
|
|
}
|
|
}
|
|
return nl->TwoElemList(nl->SymbolAtom(Stream<Tuple>::BasicType()),
|
|
nl->TwoElemList(nl->SymbolAtom(Tuple::BasicType()),res));
|
|
}
|
|
|
|
|
|
CostEstimation* RenameCostEstimationFunc()
|
|
{
|
|
return new RenameCostEstimation();
|
|
}
|
|
|
|
/*
|
|
|
|
5.12.2 Value mapping function of operator ~rename~
|
|
|
|
*/
|
|
int Rename(Word* args, Word& result, int message,
|
|
Word& local, Supplier s)
|
|
{
|
|
Word t;
|
|
Tuple* 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 = (Tuple*)t.addr;
|
|
result.setAddr(tuple);
|
|
return YIELD;
|
|
}
|
|
else return CANCEL;
|
|
|
|
case CLOSE :
|
|
|
|
qp->Close(args[0].addr);
|
|
return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
/*
|
|
|
|
5.12.3 Specification of operator ~rename~
|
|
|
|
*/
|
|
const string RenameSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
|
"\"Example\" ) "
|
|
"( <text>((stream (tuple([a1:d1, ... ,"
|
|
"an:dn)))ar) -> (stream (tuple([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--->"
|
|
") )";
|
|
|
|
|
|
|
|
const string RenameAttrSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
|
"\"Example\" ) "
|
|
"( <text> stream(tuple) x (NAME NEWNAME)* -> stream(tuple), "
|
|
"where NAME and NEWNAME in {ident, string}"
|
|
"</text--->"
|
|
"<text>_ renameAttr [ Newname1 : Oldname1 , .... ] "
|
|
"</text--->"
|
|
"<text>Renames the specified attributes. If string type is used for one of "
|
|
"the NAME or NEWNAME, it must be a constant or database object! This allows "
|
|
"for renaming attributes with forbidden names, such as operator names, type "
|
|
"names or reserved word, as 'value' or 'type'.</text--->"
|
|
"<text>query ten feed renameAttr [ No : no ] consume "
|
|
"</text--->"
|
|
") )";
|
|
|
|
|
|
const string validateAttrSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
|
"\"Example\" ) "
|
|
"( <text> stream(tuple) -> stream(tuple), "
|
|
"</text--->"
|
|
"<text>_ validateAttr "
|
|
"</text--->"
|
|
"<text>Changes the attribute names to start with an upper case"
|
|
"</text--->"
|
|
"<text>query ten feed validateAttr consume "
|
|
"</text--->"
|
|
") )";
|
|
/*
|
|
|
|
5.12.4 Definition of operator ~rename~
|
|
|
|
*/
|
|
Operator relalgrename (
|
|
"rename", // name
|
|
RenameSpec, // specification
|
|
Rename, // value mapping
|
|
Operator::SimpleSelect, // trivial selection function
|
|
RenameTypeMap, // type mapping
|
|
RenameCostEstimationFunc // cost erstimation
|
|
);
|
|
|
|
|
|
Operator relalgrenameattr (
|
|
"renameAttr", // name
|
|
RenameAttrSpec, // specification
|
|
Rename, // value mapping
|
|
Operator::SimpleSelect, // trivial selection function
|
|
RenameAttrTypeMap, // type mapping
|
|
RenameCostEstimationFunc // cost estimation
|
|
);
|
|
|
|
|
|
|
|
Operator relalgvalidateAttr (
|
|
"validateAttr", // name
|
|
validateAttrSpec, // specification
|
|
Rename, // value mapping
|
|
Operator::SimpleSelect, // trivial selection function
|
|
validateAttrTM, // type mapping
|
|
RenameCostEstimationFunc // cost estimation
|
|
);
|
|
|
|
|
|
|
|
|
|
/*
|
|
5.12 Operator ~buffer~ (Notation: !)
|
|
|
|
Collects a small initial number of tuples into a buffer before passing them to the successor. Useful for progress estimation.
|
|
|
|
5.12.1 Type mapping function of operator ~buffer~
|
|
|
|
Expects a stream of tuples and returns the same type.
|
|
|
|
---- (stream x) -> ( stream x)
|
|
----
|
|
|
|
*/
|
|
ListExpr BufferTypeMap(ListExpr args)
|
|
{
|
|
if(nl->ListLength(args)!=1){
|
|
ErrorReporter::ReportError("one argument expected");
|
|
return nl->TypeError();
|
|
}
|
|
ListExpr arg = nl->First(args);
|
|
|
|
// tuple stream
|
|
if(IsStreamDescription(arg) ){
|
|
return arg;
|
|
}
|
|
// DATA stream
|
|
ListExpr errorInfo = nl->OneElemList(nl->SymbolAtom("ERROR"));
|
|
if( nl->ListLength(arg)==2 &&
|
|
nl->IsEqual(nl->First(arg),Symbol::STREAM()) &&
|
|
am->CheckKind(Kind::DATA(),nl->Second(arg),errorInfo)) {
|
|
return arg;
|
|
}
|
|
ErrorReporter::ReportError("stream(tuple(x)), stream(DATA)"
|
|
"expected");
|
|
return nl->TypeError();
|
|
|
|
}
|
|
|
|
|
|
ListExpr BufferTypeMap2(ListExpr args)
|
|
{
|
|
if(nl->ListLength(args)!=1){
|
|
ErrorReporter::ReportError("DATA expected");
|
|
return nl->TypeError();
|
|
}
|
|
ListExpr arg = nl->First(args);
|
|
// DATA
|
|
ListExpr errorInfo = nl->OneElemList(nl->SymbolAtom("ERROR"));
|
|
if(am->CheckKind(Kind::DATA(),arg,errorInfo)){
|
|
return arg;
|
|
}
|
|
ErrorReporter::ReportError("DATA expected");
|
|
return nl->TypeError();
|
|
}
|
|
|
|
/*
|
|
|
|
|
|
5.12.2 Value mapping function of operator ~buffer~
|
|
|
|
*/
|
|
CostEstimation* BufferCostEstimationFunc()
|
|
{
|
|
return new BufferCostEstimation();
|
|
}
|
|
|
|
template<class T>
|
|
int Buffer(Word* args, Word& result, int message,
|
|
Word& local, Supplier s)
|
|
{
|
|
Word e;
|
|
T* elem;
|
|
BufferLocalInfo<T>* bli;
|
|
|
|
bli = (BufferLocalInfo<T>*) local.addr;
|
|
|
|
switch (message)
|
|
{
|
|
case OPEN :
|
|
|
|
if ( bli ) delete bli;
|
|
|
|
bli = new BufferLocalInfo<T>();
|
|
bli->state = 0;
|
|
bli->noInBuffer = 0;
|
|
bli->next = -1;
|
|
local.setAddr(bli);
|
|
|
|
qp->Open(args[0].addr);
|
|
return 0;
|
|
|
|
case REQUEST :
|
|
|
|
if ( bli->state == 2 ) //regular behaviour
|
|
//put first to avoid overhead
|
|
{
|
|
qp->Request(args[0].addr,e);
|
|
if (qp->Received(args[0].addr))
|
|
{
|
|
elem = (T*)e.addr;
|
|
result.setAddr(elem);
|
|
return YIELD;
|
|
}
|
|
else return CANCEL;
|
|
}
|
|
|
|
|
|
if ( bli->state == 0 )
|
|
{
|
|
//fill the buffer
|
|
qp->Request(args[0].addr, e);
|
|
while (qp->Received(args[0].addr) && bli->noInBuffer < BUFFERSIZE)
|
|
{
|
|
bli->buffer[bli->noInBuffer] = (T*)e.addr;
|
|
bli->noInBuffer++;
|
|
if ( bli->noInBuffer < BUFFERSIZE ) qp->Request(args[0].addr, e);
|
|
}
|
|
if ( bli->noInBuffer > 1 ){
|
|
bli->state = 1; //next from buffer
|
|
} else {
|
|
bli->state = 3; //next cancel
|
|
}
|
|
|
|
//return first tuple from the buffer, if possible
|
|
if ( bli->noInBuffer > 0 )
|
|
{
|
|
result.setAddr(bli->buffer[0]);
|
|
bli->next = 1;
|
|
return YIELD;
|
|
} else {
|
|
return CANCEL;
|
|
}
|
|
}
|
|
else if ( bli->state == 1 )
|
|
{
|
|
//return one elem from the buffer
|
|
|
|
result.setAddr(bli->buffer[bli->next]);
|
|
bli->next++;
|
|
if ( bli->next == bli->noInBuffer )
|
|
{
|
|
if ( bli->noInBuffer == BUFFERSIZE )
|
|
bli->state = 2; //next from stream
|
|
else bli->state = 3; //next cancel
|
|
}
|
|
return YIELD;
|
|
}
|
|
else {
|
|
if ( bli->state == 3 ){
|
|
return CANCEL;
|
|
} else {
|
|
cout << "Something terrible happened in the ! operator." << endl;
|
|
}
|
|
}
|
|
case CLOSE :
|
|
|
|
if ( bli )
|
|
{
|
|
delete bli;
|
|
local.setAddr(0);
|
|
}
|
|
|
|
qp->Close(args[0].addr);
|
|
return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
int Buffer2(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
result = qp->ResultStorage(s);
|
|
Attribute* arg = static_cast<Attribute*>(args[0].addr);
|
|
Attribute* res = static_cast<Attribute*>(result.addr);
|
|
res->CopyFrom(arg);
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
5.12.4 SelectionFunction and Value Mapping Array for operator ~buffer~
|
|
|
|
|
|
*/
|
|
|
|
ValueMapping BufferVM[] = {Buffer<Tuple>,Buffer<Attribute>};
|
|
|
|
int BufferSelect(ListExpr args){
|
|
ListExpr arg = nl->First(args);
|
|
ListExpr type = nl->Second(arg);
|
|
if(nl->AtomType(type)==NoAtom &&
|
|
nl->IsEqual(nl->First(type),Tuple::BasicType())){
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
5.12.4 Specification of operator ~buffer~
|
|
|
|
*/
|
|
|
|
const string BufferSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
|
"\"Example\" ) "
|
|
"( <text>stream(tuple(x)) -> stream(tuple(x)) \n"
|
|
" stream(DATA) -> stream(DATA>)</text--->"
|
|
"<text>_ !</text--->"
|
|
"<text>Collects a small number of tuples into"
|
|
" a buffer before passing them to the successor."
|
|
" Useful for progress estimation."
|
|
"</text--->"
|
|
"<text>query plz feed filter[.Ort = \"Hagen\"] ! count</text--->"
|
|
") )";
|
|
|
|
const string BufferSpec2 =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
|
"\"Example\" ) "
|
|
"( <text>DATA -> DATA </text--->"
|
|
"<text>_ !</text--->"
|
|
"<text>Does nothing</text--->"
|
|
"<text>query 1 ! </text--->"
|
|
") )";
|
|
|
|
/*
|
|
|
|
|
|
5.12.5 Definition of operator ~buffer~
|
|
|
|
*/
|
|
#ifndef USE_PROGRESS
|
|
Operator relalgbuffer (
|
|
"!", // name
|
|
BufferSpec, // specification
|
|
2,
|
|
BufferVM, // value mapping
|
|
BufferSelect, // trivial selection function
|
|
BufferTypeMap // type mapping
|
|
);
|
|
|
|
|
|
Operator relalgbuffer2 (
|
|
"!", // name
|
|
BufferSpec2, // specification
|
|
Buffer2, // value mapping
|
|
Operator::SimpleSelect, // trivial selection function
|
|
BufferTypeMap2 // type mapping
|
|
);
|
|
|
|
#else
|
|
|
|
CreateCostEstimation bufferCostEstimationList[]
|
|
= {BufferCostEstimationFunc, BufferCostEstimationFunc};
|
|
|
|
Operator relalgbuffer (
|
|
"!", // name
|
|
BufferSpec, // specification
|
|
2, // overloaded function
|
|
BufferVM, // value mapping
|
|
BufferSelect, // trivial selection function
|
|
BufferTypeMap, // type mapping
|
|
bufferCostEstimationList // cost estimation
|
|
);
|
|
|
|
Operator relalgbuffer2 (
|
|
"!", // name
|
|
BufferSpec2, // specification
|
|
Buffer2, // value mapping
|
|
Operator::SimpleSelect, // trivial selection function
|
|
BufferTypeMap2, // type mapping
|
|
BufferCostEstimationFunc // cost estimation
|
|
);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
5.13 Operator ~getFileInfo~
|
|
|
|
Returns a text object with statistical information on all files used by the
|
|
relation.
|
|
|
|
The result has format ~file\_stat\_result~:
|
|
|
|
----
|
|
file_stat_result --> (file_stat_list)
|
|
file_stat_list --> epsilon
|
|
| file_statistics file_stat_list
|
|
file_statistics --> epsilon
|
|
| file_stat_field file_statistics
|
|
file_stat_field --> ((keyname) (value))
|
|
keyname --> string
|
|
value --> string
|
|
----
|
|
|
|
5.13.1 TypeMapping of operator ~getFileInfo~
|
|
|
|
*/
|
|
|
|
ListExpr getFileInfoRelTypeMap(ListExpr args)
|
|
{
|
|
if( nl->ListLength(args)!=1 // only 1 argument
|
|
|| ( !IsRelDescription( nl->First(args), true ) // is trel
|
|
&& !IsRelDescription( nl->First(args), false ) ) ){ // is rel
|
|
return NList::typeError(
|
|
"Expected 1 single argument of type 'rel' or 'trel'.");
|
|
}
|
|
return NList(FText::BasicType()).listExpr();
|
|
}
|
|
|
|
/*
|
|
|
|
5.13.2 ValueMapping of operator ~getFileInfo~
|
|
|
|
*/
|
|
|
|
int getFileInfoRelValueMap(Word* args, Word& result, int message,
|
|
Word& local, Supplier s)
|
|
{
|
|
result = qp->ResultStorage(s);
|
|
FText* restext = (FText*)(result.addr);
|
|
GenericRelation* rel = (GenericRelation*)(args[0].addr);
|
|
SmiStatResultType resVector(0);
|
|
|
|
if ( rel != 0 ){
|
|
|
|
// start list
|
|
string resString = "[[\n";
|
|
// TupleCoreFile
|
|
rel->GetTupleFileStats(resVector);
|
|
for(SmiStatResultType::iterator i = resVector.begin();
|
|
i != resVector.end(); ){
|
|
resString += "\t[['" + i->first + "'],['" + i->second + "']]";
|
|
if(++i != resVector.end()){
|
|
resString += ",\n";
|
|
} else {
|
|
resString += "\n";
|
|
}
|
|
}
|
|
resString += "],\n";
|
|
resVector.clear();
|
|
// TupleLOBFile
|
|
rel->GetLOBFileStats(resVector);
|
|
resString += "[\n";
|
|
for(SmiStatResultType::iterator i = resVector.begin();
|
|
i != resVector.end(); ){
|
|
resString += "\t[['" + i->first + "'],['" + i->second + "']]";
|
|
if(++i != resVector.end()){
|
|
resString += ",\n";
|
|
} else {
|
|
resString += "\n";
|
|
}
|
|
}
|
|
resString += "]\n";
|
|
restext->Set(true,resString);
|
|
// end of list
|
|
resString += "]\n";
|
|
restext->Set(true,resString);
|
|
} else {
|
|
restext->Set(false,"");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
5.13.3 Specification of operator ~getFileInfo~
|
|
|
|
*/
|
|
const string getFileInfoRelSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
|
|
"( <text>(rel(tuple(x)) | trel(tuple(X)) -> text)</text--->"
|
|
"<text>getFileInfo( _ )</text--->"
|
|
"<text>Retrieve statistical infomation on the file(s) used by the relation "
|
|
"instance.</text--->"
|
|
"<text>query getFileInfo(plz)</text--->"
|
|
") )";
|
|
|
|
|
|
/*
|
|
5.13.4 Definition of operator ~getFileInfo~
|
|
|
|
*/
|
|
Operator relalggetfileinfo (
|
|
"getFileInfo", // name
|
|
getFileInfoRelSpec, // specification
|
|
getFileInfoRelValueMap, // value mapping
|
|
Operator::SimpleSelect, // trivial selection function
|
|
getFileInfoRelTypeMap // type mapping
|
|
);
|
|
|
|
|
|
/*
|
|
5.13.5 Definition of operator ~relalgfeedproject~
|
|
|
|
*/
|
|
Operator relalgfeedproject (
|
|
FeedProjectInfo(), // info
|
|
OperatorFeedProject::feedproject_vm, // value mapping
|
|
OperatorFeedProject::feedproject_tm, // type mapping
|
|
OperatorFeedProject::FeedProjectCostEstimationFunc // cost estimation
|
|
);
|
|
|
|
|
|
/*
|
|
5.14 Operator ~feedNth~
|
|
|
|
*/
|
|
ListExpr feedNthTM(ListExpr args){
|
|
string err = "rel x int x bool expected";
|
|
if(!nl->HasLength(args,3)){
|
|
return listutils::typeError(err + " (wrong number of args)");
|
|
}
|
|
if( !Relation::checkType(nl->First(args))
|
|
|| !CcInt::checkType(nl->Second(args))
|
|
|| !CcBool::checkType(nl->Third(args))){
|
|
return listutils::typeError(err);
|
|
}
|
|
return nl->TwoElemList(
|
|
listutils::basicSymbol<Stream<Tuple> >(),
|
|
nl->Second(nl->First(args)));
|
|
}
|
|
|
|
|
|
int feedNthVM(Word* args, Word& result, int message,
|
|
Word& local, Supplier s) {
|
|
|
|
typedef pair<GenericRelationIterator*, pair<int,bool> > LI;
|
|
LI* li = (LI*) local.addr;
|
|
switch(message){
|
|
case INIT : {
|
|
srand(time(0));
|
|
return 0;
|
|
}
|
|
case FINISH: {
|
|
return 0;
|
|
}
|
|
case OPEN : {
|
|
if(li){
|
|
delete li->first;
|
|
delete li;
|
|
local.addr = 0;
|
|
}
|
|
Relation* rel = (Relation*) args[0].addr;
|
|
CcInt* n = (CcInt*) args[1].addr;
|
|
CcBool* r = (CcBool*) args[2].addr;
|
|
if(!n->IsDefined() || !r->IsDefined()){
|
|
return 0;
|
|
}
|
|
int num = n->GetValue();
|
|
if(num <=0 ){
|
|
return 0;
|
|
}
|
|
local.addr = new LI(rel->MakeScan(),
|
|
pair<int,bool>(num,!r->GetValue()));
|
|
return 0;
|
|
}
|
|
case REQUEST: {
|
|
result.addr = li?li->first->GetNthTuple(li->second.first,
|
|
li->second.second)
|
|
:0;
|
|
return result.addr?YIELD:CANCEL;
|
|
}
|
|
case CLOSE:{
|
|
if(li){
|
|
delete li->first;
|
|
delete li;
|
|
local.addr = 0;
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
OperatorSpec feedNthSpec(
|
|
"rel(tuple(...)) x int x bool -> stream(tuple(...))",
|
|
"_ feedNth[_,_]",
|
|
"Returns each nth tuple from a relation. If the boolean "
|
|
"argument is false, from the block of the next n tuples "
|
|
"one is chosen randomly, otherwise exactly the nth element.",
|
|
"query plz feedNth[100,FALSE] count"
|
|
);
|
|
|
|
Operator feedNthOP(
|
|
"feedNth",
|
|
feedNthSpec.getStr(),
|
|
feedNthVM,
|
|
Operator::SimpleSelect,
|
|
feedNthTM
|
|
);
|
|
|
|
|
|
/*
|
|
Operator ~clear~
|
|
|
|
Removes the content of a relation
|
|
|
|
*/
|
|
ListExpr clearTM(ListExpr args){
|
|
if(!nl->HasLength(args,1)){
|
|
return listutils::typeError("one argument expected");
|
|
}
|
|
if(!Relation::checkType(nl->First(args))){
|
|
return listutils::typeError("relation expected");
|
|
}
|
|
return listutils::basicSymbol<CcBool>();
|
|
}
|
|
|
|
|
|
int clearVM(Word* args, Word& result, int message,
|
|
Word& local, Supplier s) {
|
|
GenericRelation* rel = (GenericRelation*) args[0].addr;
|
|
rel->Clear();
|
|
result = qp->ResultStorage(s);
|
|
((CcBool*) result.addr)->Set(true,true);
|
|
qp->SetModified(qp->GetSon(s, 0));
|
|
return 0;
|
|
}
|
|
|
|
OperatorSpec clearSpec(
|
|
"rel -> bool",
|
|
" _ clear",
|
|
"Removes all tuples from a relation and returns true",
|
|
"query ten feed consume clear"
|
|
);
|
|
|
|
Operator clearOp(
|
|
"clear",
|
|
clearSpec.getStr(),
|
|
clearVM,
|
|
Operator::SimpleSelect,
|
|
clearTM
|
|
);
|
|
|
|
|
|
/*
|
|
4.2 ~ifthenelse2~ operator
|
|
|
|
Type mapping for ~ifthenelse2~ is
|
|
|
|
---- (bool x T x T)) -> T , T in REL
|
|
----
|
|
|
|
*/
|
|
|
|
ListExpr ifthenelse2Type(ListExpr args)
|
|
{
|
|
ListExpr arg1, arg2, arg3;
|
|
|
|
if ( nl->ListLength( args ) == 3 )
|
|
{
|
|
arg1 = nl->First( args );
|
|
arg2 = nl->Second( args );
|
|
arg3 = nl->Third( args );
|
|
|
|
if (nl->Equal(arg2, arg3) && listutils::isSymbol(arg1,CcBool::BasicType()))
|
|
{
|
|
if ( IsRelDescription(arg2) || IsRelDescription(arg2, true) )
|
|
return arg2;
|
|
}
|
|
}
|
|
ErrorReporter::ReportError("Incorrect input for operator ifthenelse.");
|
|
return (nl->SymbolAtom( Symbol::TYPEERROR() ));
|
|
}
|
|
|
|
|
|
|
|
int
|
|
ifthenelse2Fun(Word* args, Word& result, int message, Word& local, Supplier s)
|
|
{
|
|
Word res(Address(0));
|
|
|
|
qp->Request(args[0].addr, res);
|
|
CcBool* arg1 = static_cast<CcBool*>( res.addr );
|
|
|
|
int index = ((arg1->IsDefined() && arg1->GetBoolval()) ? 1 : 2 );
|
|
qp->Request(args[index].addr, res);
|
|
|
|
qp->DeleteResultStorage(s);
|
|
|
|
if ( qp->IsOperatorNode(qp->GetSon(s, index))
|
|
&& !qp->IsFunctionNode(qp->GetSon(s, index)) )
|
|
{
|
|
qp->ChangeResultStorage(s, res);
|
|
qp->ReInitResultStorage(qp->GetSon(s,index));
|
|
}
|
|
else
|
|
{
|
|
Relation* r = static_cast<Relation*>( res.addr );
|
|
qp->ChangeResultStorage(s, SetWord(r->Clone()) );
|
|
}
|
|
result = qp->ResultStorage(s);
|
|
return 0;
|
|
}
|
|
|
|
const string CCSpecIfthenelse2 = "( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
|
"\"Example\" )"
|
|
"( <text>(bool x T x T) -> T </text--->"
|
|
"<text>ifthenelse2(P, R1, R2)</text--->"
|
|
"<text>Evalutes and returns the second argument R1, if the "
|
|
"boolean value expression, given as a first argument P, can be "
|
|
"evaluated to TRUE. If P evaluates to FALSE or it is undefined, "
|
|
"the third argument "
|
|
"R2 is evaluated and returned. "
|
|
"NOTE: The second and the third argument must be of the "
|
|
"same type T.</text--->"
|
|
"<text>query ifthenelse2(3 < 5, ten,"
|
|
"thousand feed consume) count</text--->"
|
|
") )";
|
|
|
|
Operator ccopifthenelse2( "ifthenelse2", CCSpecIfthenelse2, ifthenelse2Fun,
|
|
Operator::SimpleSelect, ifthenelse2Type );
|
|
|
|
|
|
|
|
/*
|
|
4.3 relcount operators
|
|
|
|
*/
|
|
|
|
/*
|
|
4.2.11 Type mapping function for the ~relcount~ operator:
|
|
|
|
string ---> int.
|
|
|
|
*/
|
|
|
|
static ListExpr relcountTM( ListExpr args ) {
|
|
if(!nl->HasLength(args,1)){
|
|
return listutils::typeError("invalid number of arguments");
|
|
}
|
|
if(!CcString::checkType(nl->First(args))){
|
|
return listutils::typeError("string expected");
|
|
}
|
|
return listutils::basicSymbol<CcInt>();
|
|
}
|
|
|
|
/*
|
|
4.20 Value mapping function of operator ~relcount~
|
|
|
|
*/
|
|
|
|
static int
|
|
RelcountFun( Word* args, Word& result, int message, Word& local, Supplier s )
|
|
{
|
|
ListExpr resultType, queryList;
|
|
QueryProcessor* qpp = 0;
|
|
OpTree tree;
|
|
string relname;
|
|
bool correct = false;
|
|
bool evaluable = false;
|
|
bool defined = false;
|
|
bool isFunction = false;
|
|
|
|
result = qp->ResultStorage( s );
|
|
// initialize result to be undefined
|
|
((CcInt *)result.addr)->Set( false, 0 );
|
|
|
|
if ( ((CcString*)args[0].addr)->IsDefined() )
|
|
{
|
|
// create the query list (count (feed <relname>))
|
|
relname = ((CcString*)args[0].addr)->GetValue();
|
|
string querystring = "(count " + relname + ")";
|
|
nl->ReadFromString(querystring, queryList);
|
|
|
|
// construct the operator tree within a new query processor instance
|
|
// NOTE: variable name for this instance must differ from qp
|
|
qpp = new QueryProcessor( nl, SecondoSystem::GetAlgebraManager() );
|
|
try{
|
|
qpp->Construct( queryList, correct,
|
|
evaluable, defined, isFunction, tree, resultType );
|
|
if ( defined && correct && evaluable )
|
|
{
|
|
// evaluate the operator tree
|
|
Word tmpresult;
|
|
qpp->EvalS( tree, tmpresult, 1 );
|
|
|
|
// create the result list ( type, value )
|
|
CcInt* TmpResult = (CcInt*) tmpresult.addr;
|
|
if(TmpResult->IsDefined()){
|
|
int count = TmpResult->GetValue();
|
|
((CcInt*) result.addr)->Set(true,count);
|
|
}
|
|
}
|
|
if(correct){
|
|
qpp->Destroy( tree, true );
|
|
}
|
|
} catch(...){}
|
|
delete qpp;
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
4.21 Value mapping function of operator ~relcount2~
|
|
|
|
*/
|
|
|
|
static int
|
|
RelcountFun2( Word* args, Word& result, int message, Word& local, Supplier s )
|
|
{
|
|
char* relname;
|
|
string querystring;
|
|
Word resultword;
|
|
string errorMessage = "";
|
|
|
|
result = qp->ResultStorage( s );
|
|
|
|
if ( ((CcString*)args[0].addr)->IsDefined() )
|
|
{
|
|
// create the query list (count (feed <relname>))
|
|
relname = (char*)(((CcString*)args[0].addr)->GetStringval());
|
|
querystring = "(count(feed " + (string)relname + "))";
|
|
|
|
// the if statement can be simply reduced to:
|
|
// if ( QueryProcessor::ExecuteQuery(querystring, result) )
|
|
if ( QueryProcessor::ExecuteQuery(querystring, resultword) )
|
|
{
|
|
((CcInt *)result.addr)->Set( true,
|
|
((CcInt*)resultword.addr)->GetIntval() );
|
|
((CcInt*)resultword.addr)->DeleteIfAllowed();
|
|
}
|
|
else cout << "Error in executing operator query: "<< errorMessage << endl;
|
|
}
|
|
else
|
|
{
|
|
((CcInt *)result.addr)->Set( false, 0 );
|
|
}
|
|
return (0);
|
|
}
|
|
const string CCSpecRelcount = "( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
|
"\"Example\" )"
|
|
"( <text>string -> int</text--->"
|
|
"<text>_ relcount</text--->"
|
|
"<text>Counts the number of tuples of a relation, "
|
|
"which is specified by its objectname"
|
|
" of type string.</text--->"
|
|
"<text>query \"Staedte\" relcount</text--->"
|
|
") )";
|
|
|
|
const string CCSpecRelcount2 = "( ( \"Signature\" \"Syntax\" \"Meaning\" "
|
|
"\"Example\" )"
|
|
"( <text>string -> int</text--->"
|
|
"<text>_ relcount2</text--->"
|
|
"<text>Counts the number of tuples of a relation, "
|
|
"which is specified by its objectname"
|
|
" of type string. Uses static method ExecuteQuery"
|
|
" from class QueryProcessor.</text--->"
|
|
"<text>query \"Orte\" relcount2</text--->"
|
|
") )";
|
|
|
|
ValueMapping ccoprelcountmap[] = { RelcountFun };
|
|
ValueMapping ccoprelcountmap2[] = { RelcountFun2 };
|
|
|
|
Operator ccoprelcount( "relcount", CCSpecRelcount, 1, ccoprelcountmap,
|
|
Operator::SimpleSelect, relcountTM );
|
|
|
|
Operator ccoprelcount2( "relcount2", CCSpecRelcount2, 1, ccoprelcountmap2,
|
|
Operator::SimpleSelect, relcountTM );
|
|
|
|
|
|
ListExpr toTextTM(ListExpr args){
|
|
if(!nl->HasLength(args,1) ){
|
|
return listutils::typeError("1 argument required");
|
|
}
|
|
if(!Tuple::checkType(nl->First(args))){
|
|
return listutils::typeError("First argument must be a tuple");
|
|
}
|
|
vector<string> names;
|
|
size_t maxLength = 0;
|
|
ListExpr attrList = nl->Second(nl->First(args));
|
|
while(!nl->IsEmpty(attrList)){
|
|
string name = nl->SymbolValue(nl->First(nl->First(attrList)));
|
|
names.push_back(name);
|
|
maxLength = name.length()>maxLength?name.length():maxLength;
|
|
attrList = nl->Rest(attrList);
|
|
}
|
|
for(size_t i=0;i<names.size();i++){
|
|
string name = names[i];
|
|
while(name.length() < maxLength){
|
|
name += " ";
|
|
}
|
|
name += " : ";
|
|
names[i] = name;
|
|
}
|
|
ListExpr appendList = nl->OneElemList(nl->StringAtom(names[0]));
|
|
ListExpr last = appendList;
|
|
for(size_t i=1; i< names.size();i++){
|
|
last = nl->Append(last, nl->StringAtom(names[i]));
|
|
}
|
|
return nl->ThreeElemList( nl->SymbolAtom(Symbols::APPEND()),
|
|
appendList,
|
|
listutils::basicSymbol<FText>());
|
|
}
|
|
|
|
|
|
int toTextVM( Word* args, Word& result, int message, Word& local, Supplier s ){
|
|
Tuple* tuple = (Tuple*) args[0].addr;
|
|
result = qp->ResultStorage(s);
|
|
FText* res = (FText*) result.addr;
|
|
vector<string> names;
|
|
for(int i=1;i<qp->GetNoSons(s);i++){
|
|
names.push_back( ((CcString*) args[i].addr)->GetValue());
|
|
}
|
|
stringstream ss;
|
|
for(size_t i=0;i<names.size();i++){
|
|
Attribute* attr = tuple->GetAttribute(i);
|
|
ss << names[i] ;
|
|
attr->Print(ss);
|
|
ss << endl;
|
|
}
|
|
res->Set(true,ss.str());
|
|
return 0;
|
|
}
|
|
|
|
OperatorSpec toTextSpec(
|
|
"tuple -> text",
|
|
"toText(_)",
|
|
"Converts a tuple into a text",
|
|
"query plz feed extend[ TT : toText(.) ] count"
|
|
);
|
|
|
|
|
|
Operator toTextOP( "toText",
|
|
toTextSpec.getStr(),
|
|
toTextVM,
|
|
Operator::SimpleSelect,
|
|
toTextTM );
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
6 Class ~RelationAlgebra~
|
|
|
|
A new subclass ~RelationAlgebra~ 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 RelationAlgebra : public Algebra
|
|
{
|
|
public:
|
|
RelationAlgebra() : Algebra()
|
|
{
|
|
ConstructorFunctions<TmpRel> cf;
|
|
cf.in = InTmpRel;
|
|
cf.out = OutTmpRel;
|
|
cf.create = CreateTmpRel;
|
|
cf.deletion = DeleteTmpRel;
|
|
cf.close = DeleteTmpRel;
|
|
cf.kindCheck = TRelKindCheck;
|
|
|
|
ConstructorInfo ci;
|
|
ci.name = TempRelation::BasicType();
|
|
ci.signature = "->trel";
|
|
ci.typeExample = "trel((tuple(A int)(B string)))";
|
|
ci.listRep = "A list of tuples";
|
|
ci.valueExample = "((1 \"Hello\") (2 \"World\") (3 \"!\"))";
|
|
ci.remarks = "Type trel represents a temporary relation."
|
|
" It is only valid during query evaluation."
|
|
" It cannot be made persistent.";
|
|
|
|
static TypeConstructor cpptrel(ci,cf);
|
|
|
|
AddTypeConstructor( &cpptuple );
|
|
AddTypeConstructor( &cpprel );
|
|
AddTypeConstructor( &cpptrel );
|
|
|
|
AddOperator(&relalgfeed);
|
|
AddOperator(&relalgconsume);
|
|
AddOperator(&relalgoconsume);
|
|
AddOperator(&relalgTUPLE);
|
|
AddOperator(&relalgTUPLE2);
|
|
AddOperator(&relalgattr);
|
|
AddOperator(&relalgfilter); relalgfilter.SetUsesArgsInTypeMapping();
|
|
AddOperator(&relalgproject);
|
|
relalgproject.enableInitFinishSupport();
|
|
AddOperator(&relalgremove);
|
|
relalgremove.enableInitFinishSupport();
|
|
AddOperator(&relalgproduct);
|
|
relalgproduct.SetUsesMemory();
|
|
relalgproduct.enableInitFinishSupport();
|
|
AddOperator(&relalgcount);
|
|
AddOperator(&relalgcount2);
|
|
AddOperator(&relalgroottuplesize);
|
|
AddOperator(&relalgexttuplesize);
|
|
AddOperator(&relalgtuplesize);
|
|
AddOperator(&memtuplesize);
|
|
AddOperator(&memattrsize);
|
|
AddOperator(&relalgrootattrsize);
|
|
AddOperator(&relalgextattrsize);
|
|
AddOperator(&relalgattrsize);
|
|
AddOperator(&relalgrename);
|
|
AddOperator(&relalgvalidateAttr);
|
|
AddOperator(&relalgrenameattr);
|
|
relalgrenameattr.SetUsesArgsInTypeMapping();
|
|
AddOperator(&relalgbuffer);
|
|
AddOperator(&relalgbuffer2);
|
|
AddOperator(&relalggetfileinfo);
|
|
|
|
AddOperator(&relalgtconsume);
|
|
|
|
// More recent programming interface for registering operators
|
|
AddOperator( SizeCountersInfo(), sizecounters_vm, sizecounters_tm );
|
|
AddOperator( DumpStreamInfo(), dumpstream_vm, dumpstream_tm );
|
|
AddOperator( ReduceInfo(), reduce_vm, reduce_tm );
|
|
AddOperator( CountBothInfo(), countboth_vm, countboth_tm );
|
|
|
|
AddOperator(&relalgfeedproject);
|
|
relalgfeedproject.enableInitFinishSupport();
|
|
AddOperator(&feedNthOP);
|
|
feedNthOP.enableInitFinishSupport();
|
|
|
|
cpptuple.AssociateKind( Kind::TUPLE() );
|
|
cpprel.AssociateKind( Kind::REL() );
|
|
cpptrel.AssociateKind( Kind::REL() );
|
|
|
|
AddOperator(&clearOp);
|
|
AddOperator( &ccopifthenelse2 );
|
|
ccopifthenelse2.SetRequestsArguments();
|
|
AddOperator( &ccoprelcount );
|
|
AddOperator( &ccoprelcount2 );
|
|
AddOperator( &toTextOP);
|
|
|
|
|
|
/*
|
|
Register operators which are able to handle progress messages
|
|
|
|
*/
|
|
#ifdef USE_PROGRESS
|
|
relalgfeed.EnableProgress();
|
|
relalgconsume.EnableProgress();
|
|
relalgoconsume.EnableProgress();
|
|
relalgtconsume.EnableProgress();
|
|
relalgfilter.EnableProgress();
|
|
relalgproject.EnableProgress();
|
|
relalgremove.EnableProgress();
|
|
relalgproduct.EnableProgress();
|
|
relalgcount.EnableProgress();
|
|
relalgrename.EnableProgress();
|
|
relalgrenameattr.EnableProgress();
|
|
relalgvalidateAttr.EnableProgress();
|
|
relalgbuffer.EnableProgress();
|
|
#endif
|
|
|
|
}
|
|
~RelationAlgebra() {};
|
|
};
|
|
|
|
|
|
/*
|
|
|
|
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*
|
|
InitializeRelationAlgebra( NestedList* nlRef, QueryProcessor* qpRef )
|
|
{
|
|
nl = nlRef;
|
|
qp = qpRef;
|
|
am = SecondoSystem::GetAlgebraManager();
|
|
return (new RelationAlgebra());
|
|
}
|
|
|