Files
secondo/Algebras/DBService2/OperatorRderive.cpp

188 lines
6.4 KiB
C++
Raw Normal View History

2026-01-23 17:03:45 +08:00
/*
1.1.1 Class Implementation
----
This file is part of SECONDO.
Copyright (C) 2017,
Faculty of Mathematics and Computer Science,
Database Systems for New Applications.
SECONDO is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
SECONDO is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with SECONDO; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
----
*/
#include "ListUtils.h"
#include "NestedList.h"
#include "StandardTypes.h"
#include "Algebras/Relation-C++/RelationAlgebra.h"
#include "Algebras/Distributed2/FileRelations.h"
#include "Algebras/DBService2/DebugOutput.hpp"
#include "Algebras/DBService2/OperatorCommon.hpp"
#include "Algebras/DBService2/OperatorRderive.hpp"
#include "Algebras/DBService2/ReplicationUtils.hpp"
#include "Algebras/DBService2/SecondoUtilsLocal.hpp"
#include "DBServiceClient.hpp"
#include "Stream.h"
#include <loguru.hpp>
using namespace std;
extern boost::recursive_mutex nlparsemtx;
namespace DBService {
ListExpr OperatorRderive::mapType(ListExpr args)
{
// rel x string x fun
LOG_F(INFO, "%s", "Acquiring lock for nlparsemtx...");
boost::lock_guard<boost::recursive_mutex> guard(nlparsemtx);
LOG_F(INFO, "%s", "Successfully acquired lock for nlparsemtx...");
if(!nl->HasLength(args,3)){
return listutils::typeError("expected 3 arguments");
}
if( !nl->HasLength(nl->First(args),2)
||!nl->HasLength(nl->Second(args),2)
||!nl->HasLength(nl->Third(args),2)){
return listutils::typeError("internal error");
}
string err = "rel x string x fun(rel->object) expected";
if(!Relation::checkType(nl->First(nl->First(args)))){
return listutils::typeError(err + " (first arg is not a relation)");
}
if(!CcString::checkType(nl->First(nl->Second(args)))){
return listutils::typeError(err + " (second arg is not a string)");
}
if(!listutils::isMap<1>(nl->First(nl->Third(args)))){
return listutils::typeError(err + " (third arg is not an unary function");
}
// the relation must be a database object
if(nl->AtomType(nl->Second(nl->First(args)))!=SymbolType){
return listutils::typeError("first argument must be a relation stored "
"in database");
}
string relname = nl->SymbolValue(nl->Second(nl->First(args)));
// JF: BUT WHY?
// the remote name (second argument) must be a constant string
// This prevents querie such as:
// query CitiesR rderive["CitiesR_count_" + num2string(1), . count]
// = CitiesR count
// These queries are required to create derivatives using dmap.
//TODO Find a different way to test the input arguments.
// if(nl->AtomType(nl->Second(nl->Second(args)))!=StringType){
// return listutils::typeError("the second arg must be a constant string");
// }
// string remoteName = nl->StringValue(nl->Second(nl->Second(args)));
// if(!stringutils::isIdent(remoteName)){
// return listutils::typeError("the second arg is not a valid identifier");
// }
ListExpr funtd = nl->Third(args);
ListExpr funt = nl->First(funtd);
ListExpr funarg = nl->Second(funt);
if(!nl->Equal(funarg, nl->First(nl->First(args)))){
return listutils::typeError("function argument and relation type differ");
}
ListExpr funres = nl->Third(funt);
if(nl->HasLength(funres,2) && nl->IsEqual(nl->First(funres),"stream")){
return listutils::typeError("function result cannot be a stream");
}
SecondoCatalog* ctlg = SecondoSystem::GetCatalog();
int algid;
int tid;
string tname;
if(!ctlg->LookUpTypeExpr(funres,tname,algid,tid)){
return listutils::typeError("function result is not a valid Secondo type");
}
ListExpr fundef = nl->Second(funtd);
// replace argumenttype in definition by the type given in type description
ListExpr fa = nl->Second(fundef);
fa = nl->TwoElemList(nl->First(fa), nl->Second(funt));
fundef = nl->ThreeElemList(nl->First(fundef), fa, nl->Third(fundef));
// we need a new QueryProcessor to avoid overwriting the internal tree
QueryProcessor* qp2 = new QueryProcessor(nl,
SecondoSystem::GetAlgebraManager());
bool correct, evaluable,defined,isFunction;
OpTree tree=0;
ListExpr resType;
try{
qp2->Construct(fundef,correct, evaluable, defined,isFunction,tree,
resType);
} catch(...){
correct = false;
}
vector<string> dbobjects;
if(correct){
qp2->GetDBObjects(tree,dbobjects);
}
if(tree){
qp2->Destroy(tree,true);
}
delete qp2;
if(!correct){
return listutils::typeError("Error in function");
}
if(!dbobjects.empty()){
return listutils::typeError("function definition cannot use any "
"database objects");
}
return nl->ThreeElemList(
nl->SymbolAtom(Symbol::APPEND()),
nl->TwoElemList( nl->StringAtom(relname),
nl->TextAtom(nl->ToString(fundef))),
funres);
}
int OperatorRderive::mapValue(Word* args,
Word& result,
int message,
Word& local,
Supplier s)
{
string relname = ((CcString*)args[3].addr)->GetValue();
string fundef = ((FText*) args[4].addr)->GetValue();
string remotename = ((CcString*)args[1].addr)->GetValue();
// remote creation of derivative on db service
string dbname = SecondoSystem::GetInstance()->GetDatabaseName();
DBServiceClient* client = DBServiceClient::getInstance();
if(client){
client->triggerDerivation(dbname, remotename, relname, fundef);
}
// local function evaluation
Relation* rel = (Relation*) args[0].addr;
Supplier fun = args[2].addr;
ArgVectorPointer funArg = qp->Argument(fun);
(*funArg)[0] = rel;
qp->Request(fun,result);
// swap result storage of fun and s
Word myResultStorage = qp->ResultStorage(s);
qp->ChangeResultStorage(fun, myResultStorage);
qp->ChangeResultStorage(s, result);
return 0;
}
} /* namespace DBService */