599 lines
20 KiB
C++
599 lines
20 KiB
C++
/*
|
|
|
|
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 <algorithm>
|
|
#include <sstream>
|
|
|
|
#include <boost/thread/mutex.hpp>
|
|
|
|
#include "CharTransform.h"
|
|
#include "NestedList.h"
|
|
#include "Profiles.h"
|
|
#include "SecParser.h"
|
|
#include "ErrorCodes.h"
|
|
|
|
#include "Algebras/DBService2/DebugOutput.hpp"
|
|
#include "Algebras/DBService2/SecondoUtilsLocal.hpp"
|
|
#include "Algebras/DBService2/TraceSettings.hpp"
|
|
#include "Algebras/DBService2/LockKeeper.hpp"
|
|
|
|
#include <loguru.hpp>
|
|
|
|
using namespace std;
|
|
using namespace distributed2;
|
|
|
|
extern CMsg cmsg;
|
|
extern boost::recursive_mutex nlparsemtx;
|
|
|
|
namespace DBService {
|
|
|
|
void SecondoUtilsLocal::readFromConfigFile(string& resultValue,
|
|
const char* section,
|
|
const char* key,
|
|
const char* defaultValue)
|
|
{
|
|
printFunction("SecondoUtilsLocal::readFromConfigFile", std::cout);
|
|
string secondoConfig = expandVar("$(SECONDO_CONFIG)");
|
|
resultValue = SmiProfile::GetParameter(section,
|
|
key, defaultValue, secondoConfig);
|
|
}
|
|
|
|
string SecondoUtilsLocal::getSecondoHomeDir() {
|
|
string secondoHome;
|
|
|
|
readFromConfigFile(secondoHome, "Environment", "SecondoHome",
|
|
"/secondo/home/is/missing");
|
|
|
|
return secondoHome;
|
|
}
|
|
|
|
bool SecondoUtilsLocal::executeQuery(const string& queryAsString)
|
|
{
|
|
// JF
|
|
Word queryResult = new Word; SetWord(Address(0));
|
|
print("Query (with new Word):", queryAsString, std::cout);
|
|
return executeQuery(queryAsString, queryResult);
|
|
}
|
|
|
|
bool SecondoUtilsLocal::prepareQueryForProcessing(
|
|
const string& queryAsString,
|
|
string& queryAsPreparedNestedListString)
|
|
{
|
|
printFunction("SecondoUtilsLocal::prepareQueryForProcessing", std::cout);
|
|
print("Query:", queryAsString, std::cout);
|
|
SecParser secondoParser;
|
|
string queryAsNestedListString;
|
|
if (secondoParser.Text2List(queryAsString, queryAsNestedListString) != 0)
|
|
{
|
|
print("could not parse query", std::cout);
|
|
return false;
|
|
}
|
|
print("query converted to nested list string", std::cout);
|
|
print("queryAsNestedListString 1", queryAsNestedListString, std::cout);
|
|
|
|
if(queryAsNestedListString.find("(query ") == 0)
|
|
{
|
|
queryAsNestedListString.erase(0, strlen("(query "));
|
|
print("queryAsNestedListString 2", queryAsNestedListString, std::cout);
|
|
queryAsPreparedNestedListString =
|
|
queryAsNestedListString.substr(
|
|
0, queryAsNestedListString.rfind(")"));
|
|
}else
|
|
{
|
|
queryAsPreparedNestedListString = queryAsNestedListString;
|
|
}
|
|
print("queryAsPreparedNestedListString",
|
|
queryAsPreparedNestedListString, std::cout);
|
|
return true;
|
|
}
|
|
|
|
bool SecondoUtilsLocal::executeQuery2(const string& queryAsString)
|
|
{
|
|
printFunction("SecondoUtilsLocal::executeQuery2", std::cout);
|
|
print("Query:", queryAsString, std::cout);
|
|
Word queryResult;
|
|
string queryAsPreparedNestedListString;
|
|
|
|
print("Acquiring lock for executeQuery2...", std::cout);
|
|
LOG_F(INFO, "%s", "Acquiring lock for utilsMutex...");
|
|
boost::lock_guard<boost::mutex> lock(utilsMutex);
|
|
LOG_F(INFO, "%s", "Successfully acquired lock for utilsMutex...");
|
|
print("Done acquiring lock for executeQuery2.", std::cout);
|
|
|
|
print("Preparing query for processing...", std::cout);
|
|
if(!prepareQueryForProcessing(
|
|
queryAsString,
|
|
queryAsPreparedNestedListString))
|
|
{
|
|
return false;
|
|
}
|
|
print("Done preparing query for processing.", std::cout);
|
|
|
|
int traceLevel =
|
|
TraceSettings::getInstance()->isDebugTraceOn() ? 3 : 0;
|
|
|
|
print("Actually executing query now ...", std::cout);
|
|
|
|
// LOG_F(INFO, "%s", "Acquiring lock for executeQuery2...");
|
|
// boost::lock_guard<boost::recursive_mutex> queryProcessorGuard(
|
|
// // Dereference the shared_ptr to the mutex
|
|
// *LockKeeper::getInstance()->getQueryProcessorMutex()
|
|
// );
|
|
// LOG_F(INFO, "%s", "Successfully acquired lock for QueryProcessorMutex.");
|
|
|
|
// // Establishing a timeout for locks
|
|
// std::shared_ptr<boost::timed_mutex> qpMutex =
|
|
// LockKeeper::getInstance()->getQueryProcessorMutex();
|
|
|
|
// boost::unique_lock<boost::timed_mutex>
|
|
// queryProcessorLock{ *qpMutex, boost::try_to_lock };
|
|
|
|
// if(queryProcessorLock.owns_lock() ||
|
|
// queryProcessorLock.try_lock_for(boost::chrono::seconds{ 360 })) {
|
|
// LOG_F(INFO, "%s", "Successfully acquired QueryProcessorMutex.");
|
|
// }
|
|
// else {
|
|
// LOG_F(ERROR, "%s", "Acquisition of QueryProcessorMutex "
|
|
// "failed due to timeout.");
|
|
// return false;
|
|
// }
|
|
|
|
return QueryProcessor::ExecuteQuery(
|
|
queryAsPreparedNestedListString,
|
|
queryResult,
|
|
DEFAULT_GLOBAL_MEMORY,
|
|
traceLevel);
|
|
}
|
|
|
|
bool SecondoUtilsLocal::executeQuery(const string& queryAsString,
|
|
Word& queryResult)
|
|
{
|
|
printFunction("SecondoUtilsLocal::executeQuery", std::cout);
|
|
|
|
print("Acquiring lock for executeQuery...", std::cout);
|
|
boost::lock_guard<boost::mutex> lock(utilsMutex);
|
|
print("Done acquiring lock for executeQuery.", std::cout);
|
|
|
|
print("QueryAsString", queryAsString, std::cout);
|
|
|
|
SecParser secondoParser;
|
|
string queryAsNestedListString;
|
|
if (secondoParser.Text2List(queryAsString, queryAsNestedListString) != 0) {
|
|
print("could not parse query", std::cout);
|
|
return false;
|
|
}
|
|
print("Query has been converted to nested list string.", std::cout);
|
|
|
|
ListExpr queryAsNestedList;
|
|
NestedList* nli = SecondoSystem::GetNestedList();
|
|
if(!nli->ReadFromString(queryAsNestedListString,
|
|
queryAsNestedList))
|
|
{
|
|
print("could not read nested list from string", std::cout);
|
|
return false;
|
|
}
|
|
|
|
print("Nested list string has been converted to nested list", std::cout);
|
|
|
|
print("QueryAsNestedListString", queryAsNestedListString, std::cout);
|
|
|
|
bool success = true;
|
|
bool correct, evaluable, defined, isFunction = false;
|
|
string typeString(""), errorString("");
|
|
|
|
// LOG_F(INFO, "%s", "Acquiring lock for executeQuery...");
|
|
// boost::lock_guard<boost::recursive_mutex> queryProcessorGuard(
|
|
// // Dereference the shared_ptr to the mutex
|
|
// *LockKeeper::getInstance()->getQueryProcessorMutex()
|
|
// );
|
|
|
|
// // Establishing a timeout for locks
|
|
// std::shared_ptr<boost::timed_mutex> qpMutex =
|
|
// LockKeeper::getInstance()->getQueryProcessorMutex();
|
|
|
|
// boost::unique_lock<boost::timed_mutex>
|
|
// queryProcessorLock{ *qpMutex, boost::try_to_lock };
|
|
|
|
// if(queryProcessorLock.owns_lock() ||
|
|
// queryProcessorLock.try_lock_for(boost::chrono::seconds{ 360 })) {
|
|
// LOG_F(INFO, "%s", "Successfully acquired QueryProcessorMutex.");
|
|
// }
|
|
// else {
|
|
// LOG_F(ERROR, "%s", "Acquisition of QueryProcessorMutex "
|
|
// "failed due to timeout.");
|
|
// return false;
|
|
// }
|
|
|
|
try
|
|
{
|
|
success = QueryProcessor::ExecuteQuery(
|
|
queryAsNestedList,
|
|
queryResult,
|
|
typeString,
|
|
errorString,
|
|
correct,
|
|
evaluable,
|
|
defined,
|
|
isFunction
|
|
/*availableMemory*/);
|
|
} catch(...)
|
|
{
|
|
print("Caught exception during query execution", std::cout);
|
|
success = false;
|
|
print("errorString", errorString, std::cout);
|
|
}
|
|
print("success", success, std::cout);
|
|
print("correct", correct, std::cout);
|
|
print("evaluable", evaluable, std::cout);
|
|
print("defined", defined, std::cout);
|
|
print("isFunction", isFunction, std::cout);
|
|
return success;
|
|
}
|
|
|
|
bool SecondoUtilsLocal::adjustDatabase(const string& databaseName)
|
|
{
|
|
printFunction("SecondoUtilsLocal::adjustDatabase", std::cout);
|
|
|
|
bool success = false;
|
|
|
|
const string currentDB = SecondoSystem::GetInstance()->GetDatabaseName();
|
|
|
|
print("Current database name", currentDB, std::cout);
|
|
print("Requested database name", databaseName, std::cout);
|
|
|
|
string databaseNameUppered(databaseName);
|
|
|
|
transform(
|
|
databaseNameUppered.begin(),
|
|
databaseNameUppered.end(),
|
|
databaseNameUppered.begin(),
|
|
::toupper);
|
|
|
|
if(currentDB
|
|
!= databaseNameUppered)
|
|
{
|
|
|
|
print("Need to switch database to", databaseName, std::cout);
|
|
|
|
// Close the current database
|
|
string queryClose("close database");
|
|
success = SecondoUtilsLocal::executeQuery(queryClose);
|
|
|
|
if (!success)
|
|
{
|
|
print("Coudln't close the current database and thus couldn't \
|
|
proceed selecting the new database.", std::cout);
|
|
|
|
return false;
|
|
}
|
|
|
|
//TODO verify if database to open already exists, only create db if
|
|
// it doesn't exist.
|
|
|
|
stringstream queryCreate;
|
|
queryCreate << "create database "
|
|
<< databaseName;
|
|
|
|
success = SecondoUtilsLocal::executeQuery(queryCreate.str());
|
|
|
|
if (!success) {
|
|
print("Coudln't create database and thus couldn't select it.",
|
|
std::cout);
|
|
return false;
|
|
}
|
|
|
|
|
|
stringstream queryOpen;
|
|
queryOpen << "open database "
|
|
<< databaseName;
|
|
|
|
success = SecondoUtilsLocal::executeQuery(queryOpen.str());
|
|
} else
|
|
{
|
|
print("database name matches, no need to adjust", std::cout);
|
|
}
|
|
return success;
|
|
}
|
|
|
|
bool
|
|
SecondoUtilsLocal::createRelation(const string& queryAsString,
|
|
string& errorMessage)
|
|
{
|
|
printFunction("SecondoUtilsLocal::createRelation", std::cout);
|
|
bool correct = false;
|
|
bool evaluable = false;
|
|
bool defined = false;
|
|
bool isFunction = false;
|
|
|
|
boost::lock_guard<boost::mutex> lock(utilsMutex);
|
|
boost::lock_guard<boost::recursive_mutex> guard(nlparsemtx);
|
|
|
|
NestedList* nli = SecondoSystem::GetNestedList();
|
|
|
|
// LOG_F(INFO, "%s", "Acquiring lock for createRelation...");
|
|
// boost::lock_guard<boost::recursive_mutex> queryProcessorGuard(
|
|
// // Dereference the shared_ptr to the mutex
|
|
// *LockKeeper::getInstance()->getQueryProcessorMutex()
|
|
// );
|
|
|
|
// // Establishing a timeout for locks
|
|
// std::shared_ptr<boost::timed_mutex> qpMutex =
|
|
// LockKeeper::getInstance()->getQueryProcessorMutex();
|
|
|
|
// boost::unique_lock<boost::timed_mutex>
|
|
// queryProcessorLock{ *qpMutex, boost::try_to_lock };
|
|
|
|
// if(queryProcessorLock.owns_lock() ||
|
|
// queryProcessorLock.try_lock_for(boost::chrono::seconds{ 360 })) {
|
|
// LOG_F(INFO, "%s", "Successfully acquired QueryProcessorMutex.");
|
|
// }
|
|
// else {
|
|
// LOG_F(ERROR, "%s", "Acquisition of QueryProcessorMutex "
|
|
// "failed due to timeout.");
|
|
// return false;
|
|
// }
|
|
|
|
QueryProcessor* queryProcessor = new QueryProcessor( nli,
|
|
SecondoSystem::GetAlgebraManager(),
|
|
DEFAULT_GLOBAL_MEMORY);
|
|
//queryProcessor->SetDebugLevel(3);
|
|
SecondoCatalog* catalog = SecondoSystem::GetCatalog();
|
|
|
|
Word result = SetWord(Address(0));
|
|
OpTree tree = 0;
|
|
|
|
ListExpr resultType = nl->TheEmptyList();
|
|
|
|
print("queryAsString", queryAsString, std::cout);
|
|
SecParser secondoParser;
|
|
string queryAsNestedListString;
|
|
if (secondoParser.Text2List(queryAsString, queryAsNestedListString) != 0) {
|
|
print("could not parse query", std::cout);
|
|
return false;
|
|
}
|
|
print("query converted to nested list string", std::cout);
|
|
ListExpr queryAsNestedList;
|
|
if (!nl->ReadFromString(queryAsNestedListString, queryAsNestedList)) {
|
|
print("could not convert string to list", std::cout);
|
|
}
|
|
print("nested list string converted to nested list", std::cout);
|
|
|
|
string objectName = nl->SymbolValue(nl->Second(queryAsNestedList));
|
|
ListExpr valueExpr = nl->Fourth(queryAsNestedList);
|
|
|
|
try {
|
|
queryProcessor->Construct(valueExpr, correct, evaluable, defined,
|
|
isFunction, tree, resultType);
|
|
|
|
if (evaluable) {
|
|
string typeName = "";
|
|
catalog->CreateObject(objectName, typeName, resultType, 0);
|
|
queryProcessor->EvalS(tree, result, 1);
|
|
catalog->UpdateObject(objectName, result);
|
|
|
|
//queryProcessor->Destroy(tree, true); // > Segfault.
|
|
queryProcessor->Destroy(tree, false);
|
|
} else {
|
|
return false;
|
|
}
|
|
} catch (...) {
|
|
|
|
print("caught error", std::cout);
|
|
queryProcessor->Destroy(tree, true);
|
|
}
|
|
|
|
cout << "correct: " << correct << endl;
|
|
cout << "evaluable: " << evaluable << endl;
|
|
cout << "defined: " << defined << endl;
|
|
cout << "isFunction: " << isFunction << endl;
|
|
return true;
|
|
}
|
|
|
|
bool SecondoUtilsLocal::executeQueryCommand(const string& queryAsString)
|
|
{
|
|
printFunction("SecondoUtilsLocal::executeQueryCommand (1 arg)", std::cout);
|
|
ListExpr resultList;
|
|
string errorMessage;
|
|
bool resultOk = SecondoUtilsLocal::executeQueryCommand(
|
|
queryAsString,
|
|
resultList,
|
|
errorMessage);
|
|
if(resultOk)
|
|
{
|
|
print("query executed successfully", std::cout);
|
|
print("resultList", resultList, std::cout);
|
|
}else
|
|
{
|
|
print("failed to execute query", std::cout);
|
|
print("errorMessage", errorMessage, std::cout);
|
|
}
|
|
return resultOk;
|
|
}
|
|
|
|
bool SecondoUtilsLocal::executeQueryCommand(const string& queryAsString,
|
|
ListExpr& resultList, string& errorMessage, bool destroyRootValue) {
|
|
printFunction("SecondoUtilsLocal::executeQueryCommand (2 args)", std::cout);
|
|
bool correct = false;
|
|
bool evaluable = false;
|
|
bool defined = false;
|
|
bool isFunction = false;
|
|
|
|
print("Acquiring lock for executeQueryCommand...", std::cout);
|
|
LOG_F(INFO, "%s", "Acquiring lock for executeQueryCommand...");
|
|
boost::lock_guard<boost::mutex> lock(utilsMutex);
|
|
|
|
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...");
|
|
|
|
// boost::lock_guard<boost::recursive_mutex> queryProcessorGuard(
|
|
// // Dereference the shared_ptr to the mutex
|
|
// *LockKeeper::getInstance()->getQueryProcessorMutex()
|
|
// );
|
|
|
|
// // Establishing a timeout for locks
|
|
// std::shared_ptr<boost::timed_mutex> qpMutex =
|
|
// LockKeeper::getInstance()->getQueryProcessorMutex();
|
|
|
|
// boost::unique_lock<boost::timed_mutex>
|
|
// queryProcessorLock{ *qpMutex, boost::try_to_lock };
|
|
|
|
// if(queryProcessorLock.owns_lock() ||
|
|
// queryProcessorLock.try_lock_for(boost::chrono::seconds{ 360 })) {
|
|
// LOG_F(INFO, "%s", "Successfully acquired QueryProcessorMutex.");
|
|
// }
|
|
// else {
|
|
// LOG_F(ERROR, "%s", "Acquisition of QueryProcessorMutex "
|
|
// "failed due to timeout.");
|
|
// return false;
|
|
// }
|
|
|
|
print("Done acquiring lock for executeQueryCommand.", std::cout);
|
|
|
|
NestedList* nli = SecondoSystem::GetNestedList();
|
|
QueryProcessor* queryProcessor = new QueryProcessor( nli,
|
|
SecondoSystem::GetAlgebraManager(),
|
|
DEFAULT_GLOBAL_MEMORY);
|
|
//queryProcessor->SetDebugLevel(3);
|
|
SecondoCatalog* catalog = SecondoSystem::GetCatalog();
|
|
|
|
Word result = SetWord(Address(0));
|
|
OpTree tree = 0;
|
|
|
|
ListExpr resultType = nl->TheEmptyList();
|
|
|
|
print("queryAsString", queryAsString, std::cout);
|
|
SecParser secondoParser;
|
|
string queryAsNestedListString;
|
|
if (secondoParser.Text2List(queryAsString, queryAsNestedListString) != 0) {
|
|
print("could not parse query", std::cout);
|
|
return false;
|
|
}
|
|
print("query converted to nested list string", std::cout);
|
|
// print("queryAsNestedListString", queryAsNestedListString, std::cout);
|
|
|
|
ListExpr queryAsNestedList;
|
|
if (!nl->ReadFromString(queryAsNestedListString, queryAsNestedList)) {
|
|
print("could not convert string to list", std::cout);
|
|
}
|
|
print("nested list string converted to nested list", std::cout);
|
|
// print("queryAsNestedList", queryAsNestedList, std::cout);
|
|
|
|
try {
|
|
print("queryProcessor->Construct", std::cout);
|
|
queryProcessor->Construct(nl->Second(queryAsNestedList), correct,
|
|
evaluable, defined, isFunction, tree, resultType);
|
|
print("trying queryProcessor->Construct done", std::cout);
|
|
cout << "correct: " << correct << endl;
|
|
cout << "evaluable: " << evaluable << endl;
|
|
cout << "defined: " << defined << endl;
|
|
cout << "isFunction: " << isFunction << endl;
|
|
|
|
if (evaluable) {
|
|
queryProcessor->EvalS(tree, result, 1);
|
|
print("queryProcessor->EvalP done", std::cout);
|
|
|
|
ListExpr valueList = catalog->OutObject(resultType, result);
|
|
print("valueList done", std::cout);
|
|
|
|
resultList = nl->TwoElemList(resultType, valueList);
|
|
print("resultList done", std::cout);
|
|
|
|
// queryProcessor->Destroy(tree, true);
|
|
queryProcessor->Destroy(tree, destroyRootValue);
|
|
print("queryProcessor->Destroy done", std::cout);
|
|
}
|
|
|
|
} catch (const std::exception& e) {
|
|
print("Caught exception in SecondoUtilsLocal::executeQueryCommand: ",
|
|
string(e.what()), std::cout);
|
|
|
|
queryProcessor->Destroy(tree, false);
|
|
return false;
|
|
} catch (SI_Error errorCode) {
|
|
stringstream errorMsg;
|
|
print("Caught SI_Error in SecondoUtilsLocal::executeQueryCommand \
|
|
with code: ", errorCode, std::cout);
|
|
|
|
print("Error descriptions of SI_Error can be found in \
|
|
SecondoInterfaceGeneral.cpp.", std::cout);
|
|
|
|
|
|
errorMsg << "CSMSG: " << cmsg.getErrorMsg() << endl;
|
|
print(errorMsg.str(), std::cout);
|
|
|
|
cout << "correct: " << correct << endl;
|
|
cout << "evaluable: " << evaluable << endl;
|
|
cout << "defined: " << defined << endl;
|
|
cout << "isFunction: " << isFunction << endl;
|
|
|
|
//queryProcessor->Destroy(tree, true);
|
|
queryProcessor->Destroy(tree, false);
|
|
return false;
|
|
|
|
} catch (...) {
|
|
print("Caught unknown exception in \
|
|
SecondoUtilsLocal::executeQueryCommand.", std::cout);
|
|
|
|
//queryProcessor->Destroy(tree, true);
|
|
queryProcessor->Destroy(tree, false);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool SecondoUtilsLocal::lookupDBServiceLocation(
|
|
string& host,
|
|
string& commPort)
|
|
{
|
|
printFunction("DBServiceConnector::lookupDBServiceLocation", std::cout);
|
|
SecondoUtilsLocal::readFromConfigFile(host,
|
|
"DBService",
|
|
"DBServiceHost",
|
|
"");
|
|
if(host.length() == 0)
|
|
{
|
|
print("could not find DBServiceHost in config file", std::cout);
|
|
return false;
|
|
}
|
|
|
|
SecondoUtilsLocal::readFromConfigFile(commPort,
|
|
"DBService",
|
|
"DBServicePort",
|
|
"");
|
|
if(commPort.length() == 0)
|
|
{
|
|
print("could not find DBServicePort in config file", std::cout);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
boost::mutex SecondoUtilsLocal::utilsMutex;
|
|
|
|
} /* namespace DBService */
|