Files
secondo/Algebras/Relation-C++/RelationAlgebra.cpp
2026-01-23 17:03:45 +08:00

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());
}