1033 lines
27 KiB
C++
1033 lines
27 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 the Common Relation Algebra
|
||
|
|
|
||
|
|
March 2003 Victor Almeida created the new Relational Algebra
|
||
|
|
organization.
|
||
|
|
|
||
|
|
Nov 2004 M. Spiekermann. Implementation of the ~Comparison~
|
||
|
|
Classes moved to RelationAlgebra.h in order to declare the
|
||
|
|
operator() as inline function. Moreover some uninitialzed
|
||
|
|
variables were set to avoid warning when compiling with
|
||
|
|
optimization flag -O2.
|
||
|
|
|
||
|
|
December 2005, Victor Almeida deleted the deprecated algebra levels
|
||
|
|
(~executable~, ~descriptive~, and ~hibrid~). Only the executable
|
||
|
|
level remains. Models are also removed from type constructors.
|
||
|
|
|
||
|
|
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.
|
||
|
|
|
||
|
|
[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.
|
||
|
|
|
||
|
|
Some functionalities are the same for both the Main Memory and the
|
||
|
|
Persistent Relational Algebra. These common functionalities belongs
|
||
|
|
to this implementation file.
|
||
|
|
|
||
|
|
2 Defines, includes, and constants
|
||
|
|
|
||
|
|
*/
|
||
|
|
#include "LogMsg.h"
|
||
|
|
#include "CharTransform.h"
|
||
|
|
|
||
|
|
#include "RelationAlgebra.h"
|
||
|
|
#include "SecondoSystem.h"
|
||
|
|
#include "QueryProcessor.h"
|
||
|
|
#include "NestedList.h"
|
||
|
|
#include "Counter.h"
|
||
|
|
#include "Symbols.h"
|
||
|
|
#include "ListUtils.h"
|
||
|
|
|
||
|
|
#include <set>
|
||
|
|
#include <string>
|
||
|
|
#include <sstream>
|
||
|
|
|
||
|
|
extern NestedList *nl;
|
||
|
|
extern QueryProcessor *qp;
|
||
|
|
extern AlgebraManager *am;
|
||
|
|
|
||
|
|
long Tuple::tuplesCreated = 0;
|
||
|
|
long Tuple::tuplesDeleted = 0;
|
||
|
|
long Tuple::maximumTuples = 0;
|
||
|
|
long Tuple::tuplesInMemory = 0;
|
||
|
|
|
||
|
|
SmiSize Tuple::extensionLimit = 256;
|
||
|
|
|
||
|
|
using namespace std;
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
These variables are used for tuple statistics.
|
||
|
|
|
||
|
|
3 Implementation of the class ~TupleType~
|
||
|
|
|
||
|
|
A ~TupleType~ is a collection (an array) of all attribute types
|
||
|
|
(~AttributeType~) of the tuple. This structure contains the
|
||
|
|
metadata of a tuple attributes.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
TupleType::TupleType( const ListExpr typeInfo ):
|
||
|
|
noAttributes(0), attrTypeArray(0),totalSize(0),refs(1),coreSize(0)
|
||
|
|
{
|
||
|
|
int i = 0;
|
||
|
|
size_t offset = sizeof(uint16_t);
|
||
|
|
|
||
|
|
try {
|
||
|
|
const string errMsg("TupleType: Wrong list format! Line ");
|
||
|
|
if ( nl->ListLength(typeInfo) != 2) { // ( <tuple> <attr_list> )
|
||
|
|
throw SecondoException(errMsg + int2Str(__LINE__));
|
||
|
|
}
|
||
|
|
noAttributes = nl->ListLength( nl->Second( typeInfo ) );
|
||
|
|
ListExpr rest = nl->Second( typeInfo );
|
||
|
|
|
||
|
|
attrTypeArray = new AttributeType[noAttributes];
|
||
|
|
|
||
|
|
while( !nl->IsEmpty( rest ) )
|
||
|
|
{
|
||
|
|
ListExpr list = nl->First( rest );
|
||
|
|
|
||
|
|
if (nl->ListLength(list) != 2){ //( <attr_name> <attr_desc> )
|
||
|
|
throw SecondoException(errMsg + int2Str(__LINE__));
|
||
|
|
}
|
||
|
|
|
||
|
|
//list = (a b ...)
|
||
|
|
ListExpr b = nl->Second( list );
|
||
|
|
rest = nl->Rest( rest );
|
||
|
|
|
||
|
|
int algId=0, typeId=0, clsSize=0;
|
||
|
|
if( nl->IsAtom(b) ){
|
||
|
|
throw SecondoException(errMsg + int2Str(__LINE__));
|
||
|
|
}
|
||
|
|
|
||
|
|
ListExpr b1 = nl->First( b );
|
||
|
|
if( nl->IsAtom( b1 ) ) //b = (b1 b2 ...)
|
||
|
|
{
|
||
|
|
if ( nl->ListLength(b) < 2 ){
|
||
|
|
throw SecondoException(errMsg + int2Str(__LINE__));
|
||
|
|
}
|
||
|
|
//b = (algid typeid ...)
|
||
|
|
algId = nl->IntValue( nl->First( b ) ),
|
||
|
|
typeId = nl->IntValue( nl->Second( b ) ),
|
||
|
|
clsSize = (am->SizeOfObj(algId, typeId))();
|
||
|
|
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
if ( nl->ListLength(b1) < 2 ){
|
||
|
|
throw SecondoException(errMsg + int2Str(__LINE__));
|
||
|
|
}
|
||
|
|
//b1 = ((algid typeid ...) ...)
|
||
|
|
algId = nl->IntValue( nl->First(b1) );
|
||
|
|
typeId = nl->IntValue( nl->Second(b1) );
|
||
|
|
clsSize = (am->SizeOfObj(algId, typeId))();
|
||
|
|
}
|
||
|
|
|
||
|
|
int currentCoreSize = 0;
|
||
|
|
TypeConstructor* tc = am->GetTC(algId, typeId);
|
||
|
|
|
||
|
|
int numOfFlobs = tc->NumOfFLOBs();
|
||
|
|
bool extStorage = false;
|
||
|
|
if ( tc->GetStorageType() == Attribute::Extension )
|
||
|
|
{
|
||
|
|
currentCoreSize = sizeof(uint32_t);
|
||
|
|
extStorage = true;
|
||
|
|
}
|
||
|
|
else if ( tc->GetStorageType() == Attribute::Default )
|
||
|
|
{
|
||
|
|
currentCoreSize = clsSize;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
currentCoreSize = tc->SerializedFixSize();
|
||
|
|
}
|
||
|
|
|
||
|
|
//totalSize += clsSize;
|
||
|
|
totalSize += currentCoreSize;
|
||
|
|
attrTypeArray[i++] = AttributeType( algId, typeId, numOfFlobs,
|
||
|
|
clsSize, currentCoreSize,
|
||
|
|
extStorage, offset );
|
||
|
|
coreSize += currentCoreSize;
|
||
|
|
offset += currentCoreSize;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
catch (SecondoException& e) {
|
||
|
|
cerr << e.msg() << endl;
|
||
|
|
cerr << "Input list: " << nl->ToString(typeInfo) << endl;
|
||
|
|
cerr << "Assuming list: "
|
||
|
|
<< "(a1 (algid typeid) a2 (algid typeid) ....) or" << endl;
|
||
|
|
cerr << " "
|
||
|
|
<< "(a1 ((algid typeid)) a2 ((algid typeid)) ....) " << endl;
|
||
|
|
assert(false);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
4 Implementation of the class ~Tuple~
|
||
|
|
|
||
|
|
*/
|
||
|
|
Tuple *Tuple::Clone() const
|
||
|
|
{
|
||
|
|
Counter::getRef("RA:ClonedTuples")++;
|
||
|
|
Tuple *result = new Tuple( this->GetTupleType() );
|
||
|
|
for( int i = 0; i < this->GetNoAttributes(); i++ )
|
||
|
|
{
|
||
|
|
Attribute* tmp = GetAttribute(i);
|
||
|
|
Attribute *attr = tmp?tmp->Clone():0;
|
||
|
|
result->PutAttribute( i, attr );
|
||
|
|
}
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
ListExpr Tuple::wrap(ListExpr attrList, bool check /*=true*/){
|
||
|
|
if(check){
|
||
|
|
if(!listutils::isAttrList(attrList)){
|
||
|
|
return listutils::typeError();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return nl->TwoElemList( listutils::basicSymbol<Tuple>(),
|
||
|
|
attrList);
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
void Tuple::InitCounters(const bool val)
|
||
|
|
{
|
||
|
|
tuplesCreated = 0;
|
||
|
|
tuplesDeleted = 0;
|
||
|
|
maximumTuples = 0;
|
||
|
|
tuplesInMemory = 0;
|
||
|
|
|
||
|
|
Counter::getRef(Symbol::CTR_CreatedTuples()) = 0;
|
||
|
|
Counter::getRef(Symbol::CTR_DeletedTuples()) = 0;
|
||
|
|
Counter::getRef(Symbol::CTR_MaxmemTuples()) = 0;
|
||
|
|
Counter::getRef(Symbol::CTR_MemTuples()) = 0;
|
||
|
|
|
||
|
|
Counter::reportValue(Symbol::CTR_CreatedTuples(), val );
|
||
|
|
Counter::reportValue(Symbol::CTR_DeletedTuples(), val);
|
||
|
|
Counter::reportValue(Symbol::CTR_MaxmemTuples(), val);
|
||
|
|
Counter::reportValue(Symbol::CTR_MemTuples(), val);
|
||
|
|
}
|
||
|
|
|
||
|
|
void Tuple::SetCounterValues()
|
||
|
|
{
|
||
|
|
Counter::getRef(Symbol::CTR_CreatedTuples()) = tuplesCreated;
|
||
|
|
Counter::getRef(Symbol::CTR_DeletedTuples()) = tuplesDeleted;
|
||
|
|
Counter::getRef(Symbol::CTR_MaxmemTuples()) = maximumTuples;
|
||
|
|
Counter::getRef(Symbol::CTR_MemTuples()) = tuplesInMemory;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
void Tuple::bringToMemory()
|
||
|
|
{
|
||
|
|
for(int i=0;i<GetNoAttributes();i++){
|
||
|
|
GetAttribute(i)->bringToMemory();
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
ostream &operator<< (ostream &os, Attribute &attrib)
|
||
|
|
{
|
||
|
|
return attrib.Print(os);
|
||
|
|
}
|
||
|
|
|
||
|
|
ostream& operator <<( ostream& o, const Tuple& t )
|
||
|
|
{
|
||
|
|
o << "<";
|
||
|
|
for( int i = 0; i < t.GetNoAttributes(); i++)
|
||
|
|
{
|
||
|
|
o << *t.GetAttribute(i);
|
||
|
|
if (i < t.GetNoAttributes() - 1)
|
||
|
|
o << ", ";
|
||
|
|
}
|
||
|
|
return o << ">";
|
||
|
|
}
|
||
|
|
|
||
|
|
Tuple *Tuple::In( ListExpr typeInfo, ListExpr value, int errorPos,
|
||
|
|
ListExpr& errorInfo, bool& correct )
|
||
|
|
{
|
||
|
|
int attrno, algebraId, typeId, noOfAttrs;
|
||
|
|
Word attr;
|
||
|
|
bool valueCorrect;
|
||
|
|
ListExpr first, firstvalue, valuelist, attrlist;
|
||
|
|
|
||
|
|
attrno = 0;
|
||
|
|
noOfAttrs = 0;
|
||
|
|
Tuple *t = new Tuple( nl->First( typeInfo ) );
|
||
|
|
|
||
|
|
attrlist = nl->Second(nl->First(typeInfo));
|
||
|
|
valuelist = value;
|
||
|
|
|
||
|
|
correct = true;
|
||
|
|
if (nl->IsAtom(valuelist))
|
||
|
|
{
|
||
|
|
correct = false;
|
||
|
|
|
||
|
|
cout << "Error in reading tuple: an atom instead of a list "
|
||
|
|
<< "of values." << endl;
|
||
|
|
cout << "Tuple no." << errorPos << endl;
|
||
|
|
cout << "The tuple is: " << endl;
|
||
|
|
nl->WriteListExpr(value);
|
||
|
|
|
||
|
|
errorInfo = nl->Append(errorInfo,
|
||
|
|
nl->FourElemList(
|
||
|
|
nl->IntAtom(71),
|
||
|
|
nl->SymbolAtom(Tuple::BasicType()),
|
||
|
|
nl->IntAtom(1),
|
||
|
|
nl->IntAtom(errorPos)));
|
||
|
|
delete t;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
while (!nl->IsEmpty(attrlist))
|
||
|
|
{
|
||
|
|
first = nl->First(attrlist);
|
||
|
|
attrlist = nl->Rest(attrlist);
|
||
|
|
|
||
|
|
algebraId =
|
||
|
|
t->GetTupleType()->GetAttributeType( attrno ).algId;
|
||
|
|
typeId =
|
||
|
|
t->GetTupleType()->GetAttributeType( attrno ).typeId;
|
||
|
|
attrno++;
|
||
|
|
if (nl->IsEmpty(valuelist))
|
||
|
|
{
|
||
|
|
correct = false;
|
||
|
|
|
||
|
|
cout << "Error in reading tuple: list of values is empty."
|
||
|
|
<< endl;
|
||
|
|
cout << "Tuple no." << errorPos << endl;
|
||
|
|
cout << "The tuple is: " << endl;
|
||
|
|
nl->WriteListExpr(value);
|
||
|
|
|
||
|
|
errorInfo = nl->Append(errorInfo,
|
||
|
|
nl->FourElemList(
|
||
|
|
nl->IntAtom(71),
|
||
|
|
nl->SymbolAtom(Tuple::BasicType()),
|
||
|
|
nl->IntAtom(2),
|
||
|
|
nl->IntAtom(errorPos)));
|
||
|
|
delete t;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
firstvalue = nl->First(valuelist);
|
||
|
|
valuelist = nl->Rest(valuelist);
|
||
|
|
|
||
|
|
attr = (am->InObj(algebraId, typeId))
|
||
|
|
(nl->First(nl->Rest(first)), firstvalue,
|
||
|
|
attrno, errorInfo, valueCorrect);
|
||
|
|
if (valueCorrect)
|
||
|
|
{
|
||
|
|
correct = true;
|
||
|
|
|
||
|
|
t->PutAttribute(attrno - 1, (Attribute *)attr.addr);
|
||
|
|
noOfAttrs++;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
correct = false;
|
||
|
|
|
||
|
|
cout << "Error in reading tuple: "
|
||
|
|
<< "wrong attribute value representation." << endl;
|
||
|
|
cout << "Tuple no." << errorPos << endl;
|
||
|
|
cout << "The tuple is: " << endl;
|
||
|
|
nl->WriteListExpr(value);
|
||
|
|
cout << endl << "The attribute is: " << endl;
|
||
|
|
nl->WriteListExpr(firstvalue);
|
||
|
|
cout << endl;
|
||
|
|
|
||
|
|
errorInfo = nl->Append(errorInfo,
|
||
|
|
nl->FiveElemList(
|
||
|
|
nl->IntAtom(71),
|
||
|
|
nl->SymbolAtom(Tuple::BasicType()),
|
||
|
|
nl->IntAtom(3),
|
||
|
|
nl->IntAtom(errorPos),
|
||
|
|
nl->IntAtom(attrno)));
|
||
|
|
delete t;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (!nl->IsEmpty(valuelist))
|
||
|
|
{
|
||
|
|
correct = false;
|
||
|
|
|
||
|
|
cout << "Error in reading tuple: "
|
||
|
|
<< "too many attribute values." << endl;
|
||
|
|
cout << "Tuple no." << errorPos << endl;
|
||
|
|
cout << "The tuple is: " << endl;
|
||
|
|
nl->WriteListExpr(value);
|
||
|
|
|
||
|
|
errorInfo = nl->Append(errorInfo,
|
||
|
|
nl->FourElemList(
|
||
|
|
nl->IntAtom(71),
|
||
|
|
nl->SymbolAtom(Tuple::BasicType()),
|
||
|
|
nl->IntAtom(4),
|
||
|
|
nl->IntAtom(errorPos)));
|
||
|
|
delete t;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return t;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
Expects a nested List expression with format
|
||
|
|
((tuple ((ident type)..(ident type))))
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
ListExpr Tuple::Out( ListExpr typeInfo )
|
||
|
|
{
|
||
|
|
int attrno=0, algebraId=0, typeId=0;
|
||
|
|
ListExpr l = nl->TheEmptyList();
|
||
|
|
ListExpr lastElem=l, attrlist=l, first=l, valuelist=l;
|
||
|
|
|
||
|
|
attrlist = nl->Second(nl->First(typeInfo));
|
||
|
|
attrno = 0;
|
||
|
|
l = nl->TheEmptyList();
|
||
|
|
while (!nl->IsEmpty(attrlist))
|
||
|
|
{
|
||
|
|
first = nl->First(attrlist);
|
||
|
|
attrlist = nl->Rest(attrlist);
|
||
|
|
|
||
|
|
algebraId = GetTupleType()->GetAttributeType( attrno ).algId;
|
||
|
|
typeId = GetTupleType()->GetAttributeType( attrno ).typeId;
|
||
|
|
Attribute *attr = GetAttribute( attrno );
|
||
|
|
valuelist = (am->OutObj(algebraId, typeId))
|
||
|
|
(nl->First(nl->Rest(first)), SetWord(attr));
|
||
|
|
attrno++;
|
||
|
|
|
||
|
|
if (l == nl->TheEmptyList())
|
||
|
|
{
|
||
|
|
l = nl->Cons(valuelist, nl->TheEmptyList());
|
||
|
|
lastElem = l;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
lastElem = nl->Append(lastElem, valuelist);
|
||
|
|
}
|
||
|
|
return l;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
5 Implementation of the class ~Relation~
|
||
|
|
|
||
|
|
*/
|
||
|
|
Tuple *Relation::GetTuple( const TupleId& id,
|
||
|
|
const int attrIndex,
|
||
|
|
const vector< pair<int, int> >& intervals,
|
||
|
|
const bool dontReportError ) const
|
||
|
|
{
|
||
|
|
Tuple *t = 0;
|
||
|
|
if( (t = GetTuple( id, dontReportError )) != 0 )
|
||
|
|
t->GetAttribute( attrIndex )->Restrict( intervals );
|
||
|
|
return t;
|
||
|
|
}
|
||
|
|
|
||
|
|
GenericRelation *Relation::In( ListExpr typeInfo, ListExpr value,
|
||
|
|
int errorPos, ListExpr& errorInfo,
|
||
|
|
bool& correct, bool tupleBuf /*=false*/)
|
||
|
|
{
|
||
|
|
ListExpr tuplelist, TupleTypeInfo, first;
|
||
|
|
GenericRelation* rel;
|
||
|
|
Tuple* tupleaddr;
|
||
|
|
int tupleno, count;
|
||
|
|
bool tupleCorrect;
|
||
|
|
|
||
|
|
correct = true;
|
||
|
|
count = 0;
|
||
|
|
|
||
|
|
if (tupleBuf)
|
||
|
|
rel = new TupleBuffer;
|
||
|
|
else
|
||
|
|
rel = new Relation( typeInfo );
|
||
|
|
|
||
|
|
|
||
|
|
tuplelist = value;
|
||
|
|
TupleTypeInfo = nl->TwoElemList(nl->Second(typeInfo),
|
||
|
|
nl->IntAtom(nl->ListLength(nl->Second(nl->Second(typeInfo)))));
|
||
|
|
tupleno = 0;
|
||
|
|
if (nl->IsAtom(value))
|
||
|
|
{
|
||
|
|
correct = false;
|
||
|
|
errorInfo = nl->Append(errorInfo,
|
||
|
|
nl->ThreeElemList(
|
||
|
|
nl->IntAtom(70),
|
||
|
|
nl->SymbolAtom(Relation::BasicType()),
|
||
|
|
tuplelist));
|
||
|
|
return rel;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{ // increase tupleno
|
||
|
|
while (!nl->IsEmpty(tuplelist))
|
||
|
|
{
|
||
|
|
first = nl->First(tuplelist);
|
||
|
|
tuplelist = nl->Rest(tuplelist);
|
||
|
|
tupleno++;
|
||
|
|
tupleaddr = Tuple::In(TupleTypeInfo, first, tupleno,
|
||
|
|
errorInfo, tupleCorrect);
|
||
|
|
|
||
|
|
if (tupleCorrect)
|
||
|
|
{
|
||
|
|
rel->AppendTuple(tupleaddr);
|
||
|
|
tupleaddr->DeleteIfAllowed();
|
||
|
|
|
||
|
|
count++;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
correct = false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!correct)
|
||
|
|
{
|
||
|
|
errorInfo =
|
||
|
|
nl->Append(errorInfo,
|
||
|
|
nl->TwoElemList(
|
||
|
|
nl->IntAtom(72),
|
||
|
|
nl->SymbolAtom(Relation::BasicType())));
|
||
|
|
delete rel;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
return rel;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
ListExpr Relation::Out( ListExpr typeInfo, GenericRelationIterator* rit )
|
||
|
|
{
|
||
|
|
Tuple* t=0;
|
||
|
|
ListExpr l=nl->TheEmptyList();
|
||
|
|
ListExpr lastElem=l, tlist=l, tupleTypeInfo=l;
|
||
|
|
|
||
|
|
//RelationIterator* rit = MakeScan();
|
||
|
|
|
||
|
|
//cerr << "OutRel " << endl;
|
||
|
|
while ( (t = rit->GetNextTuple()) != 0 )
|
||
|
|
{
|
||
|
|
tupleTypeInfo = nl->TwoElemList(
|
||
|
|
nl->Second(typeInfo),
|
||
|
|
nl->IntAtom(nl->ListLength(nl->Second(nl->Second(typeInfo)))));
|
||
|
|
tlist = t->Out(tupleTypeInfo);
|
||
|
|
//cout << "REL:" << nl->ToString(tlist) << endl;
|
||
|
|
t->DeleteIfAllowed();
|
||
|
|
if (l == nl->TheEmptyList())
|
||
|
|
{
|
||
|
|
l = nl->Cons(tlist, nl->TheEmptyList());
|
||
|
|
lastElem = l;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
lastElem = nl->Append(lastElem, tlist);
|
||
|
|
}
|
||
|
|
delete rit;
|
||
|
|
return l;
|
||
|
|
}
|
||
|
|
|
||
|
|
std::ostream& Relation::Print(std::ostream& os) const
|
||
|
|
{
|
||
|
|
os << "Start of Relation: " << endl;
|
||
|
|
int i = 0;
|
||
|
|
Tuple* t = 0;
|
||
|
|
GenericRelationIterator* it = MakeScan();
|
||
|
|
while ((t = it->GetNextTuple()) != 0)
|
||
|
|
{
|
||
|
|
os << i << ".Tuple: ";
|
||
|
|
t->Print(os);
|
||
|
|
t->DeleteIfAllowed();
|
||
|
|
t = 0;
|
||
|
|
i++;
|
||
|
|
os << endl;
|
||
|
|
}
|
||
|
|
delete it;
|
||
|
|
it = 0;
|
||
|
|
os << "End of Relation." << endl;
|
||
|
|
return os;
|
||
|
|
}
|
||
|
|
/*
|
||
|
|
6 Implementation of class ~TupleBuffer~
|
||
|
|
|
||
|
|
*/
|
||
|
|
Tuple *TupleBuffer::GetTuple( const TupleId& id,
|
||
|
|
const int attrIndex,
|
||
|
|
const vector< pair<int, int> >& intervals,
|
||
|
|
const bool dontReportError ) const
|
||
|
|
{
|
||
|
|
Tuple *t = 0;
|
||
|
|
if( (t = GetTuple( id, dontReportError )) != 0 )
|
||
|
|
t->GetAttribute( attrIndex )->Restrict( intervals );
|
||
|
|
return t;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
6 Auxilary Functions
|
||
|
|
|
||
|
|
6.2 Function ~FindAttribute~
|
||
|
|
|
||
|
|
Here ~list~ should be a list of pairs of the form
|
||
|
|
(~name~,~datatype~). The function ~FindAttribute~ determines
|
||
|
|
whether ~attrname~ occurs as one of the names in this list. If so,
|
||
|
|
the index in the list (counting from 1) is returned and the
|
||
|
|
corresponding datatype is returned in ~attrtype~. Otherwise 0 is
|
||
|
|
returned. Used in operator ~attr~, for example.
|
||
|
|
|
||
|
|
*/
|
||
|
|
int
|
||
|
|
FindAttribute( ListExpr list, string attrname, ListExpr& attrtype)
|
||
|
|
{
|
||
|
|
ListExpr first, rest;
|
||
|
|
int j;
|
||
|
|
string name;
|
||
|
|
|
||
|
|
if (nl->IsAtom(list))
|
||
|
|
return 0;
|
||
|
|
rest = list;
|
||
|
|
j = 1;
|
||
|
|
while (!nl->IsEmpty(rest))
|
||
|
|
{
|
||
|
|
first = nl->First(rest);
|
||
|
|
rest = nl->Rest(rest);
|
||
|
|
if ((nl->ListLength(first) == 2) &&
|
||
|
|
(nl->AtomType(nl->First(first)) == SymbolType))
|
||
|
|
{
|
||
|
|
name = nl->SymbolValue(nl->First(first));
|
||
|
|
if (name == attrname)
|
||
|
|
{
|
||
|
|
attrtype = nl->Second(first);
|
||
|
|
return j;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
return 0; // typeerror
|
||
|
|
j++;
|
||
|
|
}
|
||
|
|
return 0; // attrname not found
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
6.3 Function ~ConcatLists~
|
||
|
|
|
||
|
|
Concatenates two lists.
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr ConcatLists( ListExpr list1, ListExpr list2)
|
||
|
|
{
|
||
|
|
if (nl->IsEmpty(list1))
|
||
|
|
return list2;
|
||
|
|
else
|
||
|
|
return nl->Cons(nl->First(list1),
|
||
|
|
ConcatLists(nl->Rest(list1), list2));
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
6.4 Function ~AttributesAreDisjoint~
|
||
|
|
|
||
|
|
Checks wether two ListExpressions are of the form
|
||
|
|
((a1 t1) ... (ai ti)) and ((b1 d1) ... (bj dj))
|
||
|
|
and whether the ai and the bi are disjoint.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
bool insertArelNames (set<string>& aNames, ListExpr a)
|
||
|
|
{
|
||
|
|
ListExpr rest = nl->Second(nl->Second(a));
|
||
|
|
ListExpr current;
|
||
|
|
while(!nl->IsEmpty(rest))
|
||
|
|
{
|
||
|
|
current = nl->First(rest);
|
||
|
|
rest = nl->Rest(rest);
|
||
|
|
if((nl->ListLength(current) == 2))
|
||
|
|
{
|
||
|
|
if ((nl->IsAtom(nl->First(current)))
|
||
|
|
&& (nl->AtomType(nl->First(current)) == SymbolType)
|
||
|
|
&& (((nl->IsAtom(nl->Second(current)))
|
||
|
|
&& (nl->AtomType(nl->Second(current)) == SymbolType))))
|
||
|
|
aNames.insert(nl->SymbolValue(nl->First(current)));
|
||
|
|
else if (((nl->IsAtom(nl->First(nl->Second(current))))
|
||
|
|
&& (nl->AtomType(nl->First(nl->Second(current))) == SymbolType))
|
||
|
|
&& (nl->SymbolValue(nl->First(nl->Second(current))) == "arel"))
|
||
|
|
|
||
|
|
{
|
||
|
|
aNames.insert(nl->SymbolValue(nl->First(current)));
|
||
|
|
if (!insertArelNames ( aNames, nl->Second(current)))
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool checkArelNames (set<string>& aNames, ListExpr b)
|
||
|
|
{
|
||
|
|
ListExpr rest = nl->Second(nl->Second(b));
|
||
|
|
ListExpr current;
|
||
|
|
while(!nl->IsEmpty(rest))
|
||
|
|
{
|
||
|
|
current = nl->First(rest);
|
||
|
|
rest = nl->Rest(rest);
|
||
|
|
if((nl->ListLength(current) == 2)
|
||
|
|
&& (nl->IsAtom(nl->First(current)))
|
||
|
|
&& (nl->AtomType(nl->First(current)) == SymbolType))
|
||
|
|
{
|
||
|
|
if ((nl->IsAtom(nl->Second(current)))
|
||
|
|
&& (nl->AtomType(nl->Second(current)) == SymbolType))
|
||
|
|
{
|
||
|
|
if(aNames.find(nl->SymbolValue(nl->First(current))) !=
|
||
|
|
aNames.end())
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
else if ((nl->IsAtom(nl->First(nl->Second(current))))
|
||
|
|
&& (nl->AtomType(nl->First(nl->Second(current))) == SymbolType)
|
||
|
|
&& (nl->SymbolValue(nl->First(nl->Second(current))) == "arel"))
|
||
|
|
{
|
||
|
|
if(aNames.find(nl->SymbolValue(nl->First(current))) !=
|
||
|
|
aNames.end())
|
||
|
|
return false;
|
||
|
|
if(!checkArelNames(aNames, nl->Second(current)))
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool AttributesAreDisjoint(ListExpr a, ListExpr b)
|
||
|
|
{
|
||
|
|
set<string> aNames;
|
||
|
|
ListExpr rest = a;
|
||
|
|
ListExpr current;
|
||
|
|
|
||
|
|
while(!nl->IsEmpty(rest))
|
||
|
|
{
|
||
|
|
current = nl->First(rest);
|
||
|
|
rest = nl->Rest(rest);
|
||
|
|
if((nl->ListLength(current) == 2) && (nl->IsAtom(nl->First(current)))
|
||
|
|
&& (nl->AtomType(nl->First(current)) == SymbolType))
|
||
|
|
{
|
||
|
|
if ((nl->IsAtom(nl->Second(current)))
|
||
|
|
&& (nl->AtomType(nl->Second(current)) == SymbolType))
|
||
|
|
aNames.insert(nl->SymbolValue(nl->First(current)));
|
||
|
|
else if ((nl->IsAtom(nl->First(nl->Second(current))))
|
||
|
|
&& (nl->AtomType(nl->First(nl->Second(current))) == SymbolType)
|
||
|
|
&& (nl->SymbolValue(nl->First(nl->Second(current))) == "arel"))
|
||
|
|
{
|
||
|
|
aNames.insert(nl->SymbolValue(nl->First(current)));
|
||
|
|
if (!insertArelNames ( aNames, nl->Second(current)))
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
rest = b;
|
||
|
|
while(!nl->IsEmpty(rest))
|
||
|
|
{
|
||
|
|
ListExpr current = nl->First(rest);
|
||
|
|
rest = nl->Rest(rest);
|
||
|
|
if((nl->ListLength(current) == 2)
|
||
|
|
&& (nl->IsAtom(nl->First(current)))
|
||
|
|
&& (nl->AtomType(nl->First(current)) == SymbolType))
|
||
|
|
{
|
||
|
|
if ((nl->IsAtom(nl->Second(current)))
|
||
|
|
&& (nl->AtomType(nl->Second(current)) == SymbolType))
|
||
|
|
{
|
||
|
|
if(aNames.find(nl->SymbolValue(nl->First(current))) !=
|
||
|
|
aNames.end())
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
else if ((nl->IsAtom(nl->First(nl->Second(current))))
|
||
|
|
&& (nl->AtomType(nl->First(nl->Second(current))) == SymbolType)
|
||
|
|
&& (nl->SymbolValue(nl->First(nl->Second(current))) == "arel"))
|
||
|
|
{
|
||
|
|
if(aNames.find(nl->SymbolValue(nl->First(current))) !=
|
||
|
|
aNames.end())
|
||
|
|
return false;
|
||
|
|
if(!checkArelNames(aNames, nl->Second(current)))
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
6.6 Function ~CompareNames~
|
||
|
|
|
||
|
|
*/
|
||
|
|
bool CompareNames(ListExpr list)
|
||
|
|
{
|
||
|
|
vector<string> attrnamestrlist;
|
||
|
|
vector<string>::iterator it;
|
||
|
|
ListExpr attrnamelist;
|
||
|
|
int unique;
|
||
|
|
string attrname;
|
||
|
|
|
||
|
|
attrnamelist = list;
|
||
|
|
attrnamestrlist.resize(nl->ListLength(list));
|
||
|
|
it = attrnamestrlist.begin();
|
||
|
|
while (!nl->IsEmpty(attrnamelist))
|
||
|
|
{
|
||
|
|
attrname = nl->SymbolValue(nl->First(nl->First(attrnamelist)));
|
||
|
|
attrnamelist = nl->Rest(attrnamelist);
|
||
|
|
unique = std::count(attrnamestrlist.begin(),
|
||
|
|
attrnamestrlist.end(),
|
||
|
|
attrname);
|
||
|
|
*it = attrname;
|
||
|
|
if (unique) return false;
|
||
|
|
it++;
|
||
|
|
}
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
6.7 Function ~IsTupleDescription~
|
||
|
|
|
||
|
|
Checks wether a ListExpression is of the form
|
||
|
|
((a1 t1) ... (ai ti)).
|
||
|
|
|
||
|
|
*/
|
||
|
|
bool IsTupleDescription( ListExpr a )
|
||
|
|
{
|
||
|
|
ListExpr rest = a;
|
||
|
|
ListExpr current;
|
||
|
|
ListExpr errorInfo = nl->OneElemList(nl->SymbolAtom("ErrorInfo"));
|
||
|
|
|
||
|
|
if(nl->AtomType(a)!=NoAtom){
|
||
|
|
ErrorReporter::ReportError("Not a valid tuple type, must be a list.");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
if(nl->IsEmpty(a)){
|
||
|
|
ErrorReporter::ReportError("An empty attribute list is not allowed.");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
set<string> attrnames;
|
||
|
|
while(!nl->IsEmpty(rest))
|
||
|
|
{
|
||
|
|
current = nl->First(rest);
|
||
|
|
rest = nl->Rest(rest);
|
||
|
|
if(! ( (nl->ListLength(current) == 2)
|
||
|
|
&& (nl->IsAtom(nl->First(current)))
|
||
|
|
&& (nl->AtomType(nl->First(current)) == SymbolType)
|
||
|
|
&& am->CheckKind(Kind::DATA(),nl->Second(current),errorInfo))
|
||
|
|
&& attrnames.find(nl->SymbolValue(nl->First(current)))==
|
||
|
|
attrnames.end()) {
|
||
|
|
if(nl->ListLength(current!=2)){
|
||
|
|
ErrorReporter::ReportError("Attribut description must have length 2");
|
||
|
|
}
|
||
|
|
if(!nl->IsAtom(nl->First(current)) ||
|
||
|
|
(nl->AtomType(nl->First(current)) != SymbolType)){
|
||
|
|
ErrorReporter::ReportError("Attribute name must be a symbol.");
|
||
|
|
}
|
||
|
|
if(! am->CheckKind(Kind::DATA(),nl->Second(current),errorInfo)){
|
||
|
|
ErrorReporter::ReportError("Attribute type is not of kind DATA.");
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
} else {
|
||
|
|
attrnames.insert(nl->SymbolValue(nl->First(current)));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
6.7 Function ~IsRelDescription~
|
||
|
|
|
||
|
|
Checks wether a ListExpression is of the form
|
||
|
|
(rel (tuple ((a1 t1) ... (ai ti)))).
|
||
|
|
|
||
|
|
*/
|
||
|
|
bool IsRelDescription( ListExpr relDesc, bool trel /*=false*/ )
|
||
|
|
{
|
||
|
|
if( nl->ListLength(relDesc) != 2 ){
|
||
|
|
ErrorReporter::ReportError("Relation description must have length 2.");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
ListExpr relSymbol = nl->First(relDesc);
|
||
|
|
ListExpr tupleDesc = nl->Second(relDesc);
|
||
|
|
|
||
|
|
const string relStr = trel ? TempRelation::BasicType():Relation::BasicType();
|
||
|
|
|
||
|
|
if( !nl->IsAtom(relSymbol) ||
|
||
|
|
nl->AtomType(relSymbol) != SymbolType ||
|
||
|
|
nl->SymbolValue(relSymbol) != relStr ){
|
||
|
|
ErrorReporter::ReportError("Symbol '" + relStr + "' expected");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
if( nl->ListLength(tupleDesc) != 2 ){
|
||
|
|
ErrorReporter::ReportError("Tuple description must have length 2.");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
ListExpr tupleSymbol = nl->First(tupleDesc);;
|
||
|
|
ListExpr attrList = nl->Second(tupleDesc);
|
||
|
|
|
||
|
|
if( !nl->IsAtom(tupleSymbol) ||
|
||
|
|
nl->AtomType(tupleSymbol) != SymbolType ||
|
||
|
|
nl->SymbolValue(tupleSymbol) != Tuple::BasicType() ){
|
||
|
|
ErrorReporter::ReportError("The first element of a tuple description"
|
||
|
|
" must be the symbol 'tuple'.");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
if( !IsTupleDescription(attrList) )
|
||
|
|
return false;
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
6.7 Function ~IsStreamDescription~
|
||
|
|
|
||
|
|
Checks wether a ListExpression is of the form
|
||
|
|
(stream (tuple ((a1 t1) ... (ai ti)))).
|
||
|
|
|
||
|
|
*/
|
||
|
|
bool IsStreamDescription( ListExpr streamDesc )
|
||
|
|
{
|
||
|
|
if( nl->ListLength(streamDesc) != 2 ){
|
||
|
|
ErrorReporter::ReportError("A stream description must have length 2.");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
ListExpr streamSymbol = nl->First(streamDesc);
|
||
|
|
ListExpr tupleDesc = nl->Second(streamDesc);
|
||
|
|
|
||
|
|
if( !nl->IsAtom(streamSymbol) ||
|
||
|
|
nl->AtomType(streamSymbol) != SymbolType ||
|
||
|
|
nl->SymbolValue(streamSymbol) != Symbol::STREAM() ){
|
||
|
|
ErrorReporter::ReportError("Symbol 'stream' expected");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
if( nl->ListLength(tupleDesc) != 2 ){
|
||
|
|
ErrorReporter::ReportError("Tuple description must have length 2.");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
ListExpr tupleSymbol = nl->First(tupleDesc);;
|
||
|
|
ListExpr attrList = nl->Second(tupleDesc);
|
||
|
|
|
||
|
|
if( !nl->IsAtom(tupleSymbol) ||
|
||
|
|
nl->AtomType(tupleSymbol) != SymbolType ||
|
||
|
|
nl->SymbolValue(tupleSymbol) != Tuple::BasicType() ){
|
||
|
|
ErrorReporter::ReportError("The first element of a tuple description"
|
||
|
|
" must be the symbol 'tuple'.");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
if( !IsTupleDescription(attrList) )
|
||
|
|
return false;
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
6.8 Function ~GetTupleResultType~
|
||
|
|
|
||
|
|
This function returns the tuple result type as a list expression
|
||
|
|
given the Supplier ~s~.
|
||
|
|
|
||
|
|
*/
|
||
|
|
ListExpr GetTupleResultType( Supplier s )
|
||
|
|
{
|
||
|
|
|
||
|
|
/*
|
||
|
|
ListExpr result = qp->GetType( s ),
|
||
|
|
first = nl->First( result );
|
||
|
|
|
||
|
|
|
||
|
|
if(listutils::isSymbol(first,Symbols::MAP())){
|
||
|
|
result = nl->Third(result);
|
||
|
|
} else if( !listutils::isSymbol(first,Symbols::STREAM())){
|
||
|
|
assert(false);
|
||
|
|
}
|
||
|
|
|
||
|
|
first = nl->First( result );
|
||
|
|
return SecondoSystem::GetCatalog()->NumericType( result );
|
||
|
|
*/
|
||
|
|
return qp->GetNumType(s);
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
6.9 Function ~CompareSchemas~
|
||
|
|
|
||
|
|
This function receives two relation types and compare their schemas.
|
||
|
|
It returns true if they are equal, and false otherwise.
|
||
|
|
|
||
|
|
*/
|
||
|
|
bool CompareSchemas( ListExpr r1, ListExpr r2 )
|
||
|
|
{
|
||
|
|
ListExpr attrList1 = nl->Second( nl->Second( r1 ) ),
|
||
|
|
attrList2 = nl->Second( nl->Second( r2 ) );
|
||
|
|
|
||
|
|
if( nl->ListLength( attrList1 ) != nl->ListLength( attrList2 ) )
|
||
|
|
return false;
|
||
|
|
|
||
|
|
for( int i = 0; i < nl->ListLength( attrList1 ); i++ )
|
||
|
|
{
|
||
|
|
ListExpr first1 = nl->First( attrList1 ),
|
||
|
|
first2 = nl->First( attrList2 );
|
||
|
|
attrList1 = nl->Rest( attrList1 );
|
||
|
|
attrList2 = nl->Rest( attrList2 );
|
||
|
|
|
||
|
|
if( nl->SymbolValue( nl->Second( first1 ) ) !=
|
||
|
|
nl->SymbolValue( nl->Second( first2 ) ) )
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
7 Function returning the type name for ~temporal relation~
|
||
|
|
|
||
|
|
*/
|
||
|
|
const string TempRelation::BasicType() { return "trel"; }
|