Files
secondo/Algebras/PropertyGraph2/PropertyGraphQueryProcessor.cpp
2026-01-23 17:03:45 +08:00

1496 lines
41 KiB
C++

/*
----
This file is part of SECONDO.
Copyright (C) 2012, University in Hagen
Faculty of Mathematic 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 "Algebras/FText/FTextAlgebra.h"
#include "PropertyGraphQueryProcessor.h"
#include "PropertyGraph2.h"
#include "../OrderedRelation/OrderedRelationAlgebra.h"
#include "NestedList.h"
#include "ListUtils.h"
#include "Utils.h"
using namespace std;
namespace pgraph2 {
#define NO_REPEATED_EDGE_SEMANTIC
//----------------------------------------------------------------------------
PGraphQueryProcessor::~PGraphQueryProcessor()
{
if (_InputStreamAddress!=0)
qp->Close(_InputStreamAddress);
if (_InputRelationIterator!=NULL)
_InputRelationIterator=NULL;
if (tree!=NULL)
delete tree;
}
//----------------------------------------------------------------------------
PGraphQueryProcessor::PGraphQueryProcessor(PGraph2 *apg, MemoryGraphObject *pgm)
{
InputStreamState = InputStreamStateEnum::Closed;
pg=apg;
pgraphMem=pgm;
}
/*
set the input Relation for the QueryProcessor
*/
//----------------------------------------------------------------------------
void PGraphQueryProcessor::SetInputRelation(QueryTree *tree)
{
string relname = tree->Root->TypeName;
LOGOP(30,"PGraphQueryProcessor::SetInputRelation","relname: ", relname);
Relation* rel=NULL;
// node can be found by index directly
if (tree->Root->Filters.size()==1 && (tree->Root->Filters.front()->Indexed))
{
QueryFilter *qf=tree->Root->Filters.front();
string idxname=pgraphMem->name+"_idx_"+tree->Root->TypeName+"_"+qf->Name;
string memtabname=pgraphMem->name+"_rel_"+tree->Root->TypeName;
string query="";
LOGOP(10,"PGraphQueryProcessor::SetInputRelation","use index : "+idxname);
if (pg->structure =="memory"){
query="(consume (mexactmatch "+idxname+" "+memtabname+" \""+
qf->Value+"\"))";
}
else if (pg->structure=="orel"){
query="(consume (exactmatch "+idxname+" "+relname+"P \""+
qf->Value+"\"))";
}
rel=ExecuteQuery(query);
}
else
{
// open start node relation
RelationInfo *ri = pgraphMem->RelRegistry.GetRelationInfo(relname);
if (ri==NULL)
throw PGraph2Exception("relation not defined");
ListExpr reltype=SecondoSystem::GetCatalog()->GetObjectTypeExpr(ri->Name);
if (nl->IsEmpty(reltype))
throw PGraph2Exception("relation not found");
ListExpr relinfo;
LOGOP(10,"PGraphQueryProcessor::SetInputRelation","open relation : ",
ri->Name);
rel= OpenRelation(ri->Name, relinfo);
}
InputStreamState=InputStreamStateEnum::Reading;
_InputRelationIterator = rel->MakeScan();
}
//----------------------------------------------------------------------------
void PGraphQueryProcessor::SetInputStream(Address stream)
{
if (InputStreamState==InputStreamStateEnum::Reading)
throw PGraph2Exception("already reading input stream!");
_InputStreamAddress=stream;
Word rec;
qp->Open(_InputStreamAddress);
InputStreamState=InputStreamStateEnum::Reading;
}
/*
checks if the given QueryTreeBase matches to the filters of the graph
*/
//----------------------------------------------------------------------------
bool PGraphQueryProcessor::MatchesFilters(QueryTreeBase *item,
RelationSchemaInfo *schema, Tuple *tuple)
{
for (auto&& f:item->Filters)
{
AttrInfo *ai=schema->GetAttrInfo(f->Name);
if (ai!=NULL)
{
string val=ai->GetStringVal(tuple);
//LOGOP(30, "check filter:",f->Name ," ",f->Value,"=",val);
if (val!=f->Value) return false;
}
}
return true;
}
//----------------------------------------------------------------------------
bool PGraphQueryProcessor::UsedEdgeAlready(QueryTreeEdge *queryedge,
uint edgeid)
{
for(auto &&edge: poslist)
{
if (edge==queryedge) break;
if (edge->current_edgeid==edgeid) return true;
}
return false;
}
/*
get the outgoing Nodes of the actual node
*/
//-----------------------------------------------------------------------------
void PGraphQueryProcessor::GetOutGoingNodes (std::string relname, \
int localnodeid, bool reverse)
{
Word resultword;
bool defined;
if (reverse) {
relname=relname+"_B";
}
SecondoSystem::GetCatalog()->GetObject(relname, resultword, defined);
OrderedRelation* orel = (OrderedRelation*) resultword.addr;
std::vector<int> OutGoingNodes;
OrderedRelationIterator* orelIt = 0;
vector<void*> attributes(2);
vector<SmiKey::KeyDataType> kElems(2);
SmiKey test((int32_t) 0);
kElems[0] = test.GetType();
kElems[1] = test.GetType();
CcInt* minNodeId = new CcInt(true,0);
CcInt* maxNodeId = new CcInt(true,numeric_limits<int>::max());
CcInt* actNodeInt = new CcInt(true,localnodeid);
attributes[0] = actNodeInt;
attributes[1] = minNodeId;
CompositeKey actNodeLower(attributes,kElems,false);
attributes[1] = maxNodeId;
CompositeKey actNodeUpper(attributes,kElems,true);
orelIt = (OrderedRelationIterator*) orel->MakeRangeScan(actNodeLower, \
actNodeUpper);
Tuple* tuple = orelIt->GetNextTuple();
while (tuple != NULL) {
if (!reverse) {
int value = ((CcInt*)tuple->GetAttribute(1))->GetValue();
OutGoingNodes.push_back(value);
}
else if (reverse) {
int value = ((CcInt*)tuple->GetAttribute(0))->GetValue();
OutGoingNodes.push_back(value);
}
tuple = orelIt->GetNextTuple();
}
GlobalOutGoingNodes[relname][localnodeid] = OutGoingNodes;
if (orelIt!=NULL) {
delete orelIt;
orelIt=NULL;
}
if (orel!=NULL){
delete orel;
orel=NULL;
}
}
/*
check if the actual node has outgoing Edges or if they are already saved
*/
//----------------------------------------------------------------------------
bool PGraphQueryProcessor::CheckGlobalOutGoingNodes (std::string relname, \
int localnodeid, bool reverse)
{
std::map<std::string, std::map<int, std::vector<int>>>::iterator it;
std::map<int, std::vector<int>>::iterator it2;
if (reverse) relname=relname+"_B";
it = GlobalOutGoingNodes.find(relname);
if (it != GlobalOutGoingNodes.end())
{
it2 = GlobalOutGoingNodes[relname].find(localnodeid);
if (it2 != GlobalOutGoingNodes[relname].end())
{
return true;
}
}
return false;
}
/*
searching for resulttuple with the next edge
*/
//----------------------------------------------------------------------------
bool PGraphQueryProcessor::NextEdge(QueryTreeEdge *queryedge)
{
//
vector<int> *edgelist=NULL;
if (!queryedge->Reverse)
edgelist=&pgraphMem->AdjList.OutGoingRels.at(queryedge->FromNode
->current_nodeid);
else
edgelist=&pgraphMem->AdjList.InGoingRels.at(queryedge->FromNode
->current_nodeid);
// find next edge
for(uint i=queryedge->current_edgeindex+1; i<edgelist->size(); i++)
{
//
Edge *einfo=pgraphMem->AdjList.EdgeInfo[edgelist->at(i)];
LOGOP(30,"PGraphQueryProcessor::NextEdge", "checking edge index ",
queryedge->current_edgeindex, " -> ",i);
bool ok=true;
// no-repeated edge semantics neo4j
#ifdef NO_REPEATED_EDGE_SEMANTIC
if (UsedEdgeAlready(queryedge, einfo->EdgeId))
{
LOGOP(30,"PGraphQueryProcessor::MatchEdge", "edge already taken",
einfo->EdgeId);
ok=false;
}
#endif
if (ok) ok=CheckEdge(queryedge, einfo) ;
if (ok) {
LOGOP(30,"PGraphQueryProcessor::NextEdge", "next found edgeid:",
einfo->EdgeId);
int nodeid=queryedge->Reverse ? einfo->FromNodeId : einfo->ToNodeId;
queryedge->current_edgeindex=i;
queryedge->current_edgeid=einfo->EdgeId;
bool b=MatchNode(nodeid, queryedge->ToNode);
if (b) return true;
}
}
return false;
}
/*
searching for resulttuple with the next edge
*/
//----------------------------------------------------------------------------
bool PGraphQueryProcessor::NextEdge2(QueryTreeEdge *queryedge)
{
//
vector<int> *edgelist=NULL;
if (CheckGlobalOutGoingNodes(queryedge->TypeName,queryedge->FromNode->\
current_nodeid,queryedge->Reverse)) {
if (queryedge->Reverse){
string relname_b=queryedge->TypeName+"_B";
edgelist=&GlobalOutGoingNodes[relname_b][queryedge->FromNode->\
current_nodeid];
}
else {
edgelist=&GlobalOutGoingNodes[queryedge->TypeName][queryedge->\
FromNode->current_nodeid];
}
}
else
{
GetOutGoingNodes(queryedge->TypeName, queryedge->FromNode->\
current_nodeid, queryedge->Reverse);
if (queryedge->Reverse){
string relname_b=queryedge->TypeName+"_B";
edgelist=&GlobalOutGoingNodes[relname_b][queryedge->FromNode->\
current_nodeid];
}
else {
edgelist=&GlobalOutGoingNodes[queryedge->TypeName][queryedge->\
FromNode->current_nodeid];
}
}
// find next edge
for(int i=queryedge->current_edgeindex+1; \
i<static_cast<int>(edgelist->size()); i++)
{
//
// Edge *einfo=pgraphMem->AdjList.EdgeInfo[edgelist->at(i)];
LOGOP(30,"PGraphQueryProcessor::NextEdge", "checking edge index ",
queryedge->current_edgeindex, " -> ",i);
bool ok=true;
if (ok) ok=CheckEdge2(queryedge, edgelist->at(i)) ;
if (ok) {
LOGOP(30,"PGraphQueryProcessor::NextEdge", "next found edgeid:", \
queryedge->FromNode->current_nodeid);
int nodeid=edgelist->at(i);
queryedge->current_edgeindex=i;
queryedge->current_edgeid=queryedge->FromNode->current_nodeid;
queryedge->current_edge_tonodeid=nodeid;
bool b=MatchNode2(nodeid, queryedge->ToNode);
if (b) {
return true;
}
}
}
return false;
}
/*
recursive searching for result tuple
*/
//----------------------------------------------------------------------------
bool PGraphQueryProcessor::MatchEdge(QueryTreeEdge *queryedge)
{
LOGOP(30,"PGraphQueryProcessor::MatchEdge", "entering for node ",
queryedge->FromNode->current_nodeid, " Direction: ",
(queryedge->Reverse?"reverse":"forward"));
//
vector<int> *edgelist=NULL;
if (!queryedge->Reverse)
edgelist=&pgraphMem->AdjList.OutGoingRels[queryedge->FromNode
->current_nodeid];
else
edgelist=&pgraphMem->AdjList.InGoingRels[queryedge->FromNode
->current_nodeid];
// try all edges
LOGOP(30,"PGraphQueryProcessor::MatchEdge", "edgelist size: ",
edgelist->size());
for(uint i=0; i<edgelist->size(); i++)
{
Edge *einfo=pgraphMem->AdjList.EdgeInfo[edgelist->at(i)];
bool ok=true;
// no-repeated edge semantics neo4j
#ifdef NO_REPEATED_EDGE_SEMANTIC
if (UsedEdgeAlready(queryedge, einfo->EdgeId))
{
LOGOP(30,"PGraphQueryProcessor::MatchEdge", "edge already taken",
einfo->EdgeId);
ok=false;
}
#endif
LOGOP(30,"PGraphQueryProcessor::MatchEdge", "checking edge index ",i,
" [",einfo->FromNodeId," -> ",einfo->ToNodeId, "]");
if (ok) ok=CheckEdge(queryedge, einfo) ;
// edge ok - go deeper
if (ok)
{
int tonode= queryedge->Reverse ? einfo->FromNodeId : einfo->ToNodeId;
// memorize current edge index/id
queryedge->current_edgeindex=i;
queryedge->current_edgeid=einfo->EdgeId;
bool nodematched=MatchNode(tonode, queryedge->ToNode);
// found one
if (nodematched)
return true;
};
}
return false;
}
/*
recursive searching for result tuple
*/
//----------------------------------------------------------------------------
bool PGraphQueryProcessor::MatchEdge2(QueryTreeEdge *queryedge)
{
LOGOP(30,"PGraphQueryProcessor::MatchEdge", "entering for node ",
queryedge->FromNode->current_nodeid, " Direction: ",
(queryedge->Reverse?"reverse":"forward"));
//
vector<int> *edgelist=NULL;
if (CheckGlobalOutGoingNodes(queryedge->TypeName,queryedge->FromNode->\
current_nodeid,queryedge->Reverse)) {
if (queryedge->Reverse){
string relname_b=queryedge->TypeName+"_B";
edgelist=&GlobalOutGoingNodes[relname_b][queryedge->FromNode->\
current_nodeid];
}
else {
edgelist=&GlobalOutGoingNodes[queryedge->TypeName][queryedge->\
FromNode->current_nodeid];
}
}
else
{
GetOutGoingNodes(queryedge->TypeName, queryedge->FromNode->\
current_nodeid, queryedge->Reverse);
if (queryedge->Reverse){
string relname_b=queryedge->TypeName+"_B";
edgelist=&GlobalOutGoingNodes[relname_b][queryedge->FromNode->\
current_nodeid];
}
else {
edgelist=&GlobalOutGoingNodes[queryedge->TypeName][queryedge->\
FromNode->current_nodeid];
}
}
// try all edges
LOGOP(30,"PGraphQueryProcessor::MatchEdge", "edgelist size: ",
edgelist->size());
for(int i=0; i<static_cast<int>(edgelist->size()); i++)
{
//Edge *einfo=pgraphMem->AdjList.EdgeInfo[edgelist->at(i)];
bool ok=true;
LOGOP(30,"PGraphQueryProcessor::MatchEdge", "checking edge index ",i,
" [",queryedge->FromNode->current_nodeid," -> ",edgelist->at(i), "]");
if (ok) ok=CheckEdge2(queryedge, edgelist->at(i)) ;
// edge ok - go deeper
if (ok)
{
int tonode=edgelist->at(i);
// memorize current edge index/id
queryedge->current_edgeindex=i;
queryedge->current_edgeid=queryedge->FromNode->current_nodeid;
queryedge->current_edge_tonodeid=tonode;
bool nodematched=MatchNode2(tonode, queryedge->ToNode);
// found one
if (nodematched) {
return true;
}
};
}
return false;
}
/*
checks if the given QueryEdge matches to the filter of the querytree
*/
//----------------------------------------------------------------------------
bool PGraphQueryProcessor::CheckEdge(QueryTreeEdge *queryedge, Edge* edge)
{
LOGOP(30,"PGraphQueryProcessor::CheckEdge");
//queryedge->TypeName?
RelationInfo* ri = pgraphMem->RelRegistry.GetRelationInfo(edge->RelId);
Tuple *tuple=pgraphMem->AdjList.EdgeList[edge->EdgeId];
// check edge type
if ((queryedge->TypeName!="") && (queryedge->TypeName!=ri->Name))
{
LOGOP(30,"PGraphQueryProcessor::CheckEdge","typename failed");
return false;
}
// check node filters
if (!MatchesFilters(queryedge, &ri->RelSchema, tuple)) return false;
// check global filters
if (queryedge->Alias!="") {
if (!tree->filterList.Matches(queryedge->Alias, &ri->RelSchema, tuple))
return false;
}
// add alias mapping, if any
if (queryedge->Alias!="") {
aliases[queryedge->Alias]=queryedge;
}
return true;
}
/*
checks if the given QueryEdge matches to the filter of the querytree
*/
//----------------------------------------------------------------------------
bool PGraphQueryProcessor::CheckEdge2(QueryTreeEdge *queryedge, int toid)
{
LOGOP(30,"PGraphQueryProcessor::CheckEdge");
//queryedge->TypeName?
RelationInfo* ri = pgraphMem->RelRegistry.\
GetRelationInfo(queryedge->TypeName);
Word resultword;
bool defined;
string relname = queryedge->TypeName;
if (queryedge->Reverse) relname = relname+"_B";
SecondoSystem::GetCatalog()->GetObject(relname, resultword, defined);
OrderedRelation* orel = (OrderedRelation*) resultword.addr;
OrderedRelationIterator* orelIt = 0;
vector<void*> attributes(2);
vector<SmiKey::KeyDataType> kElems(2);
SmiKey test((int32_t) 0);
kElems[0] = test.GetType();
kElems[1] = test.GetType();
CcInt* minNodeId = new CcInt(true,0);
CcInt* maxNodeId = new CcInt(true,numeric_limits<int>::max());
CcInt* actNodeInt = new CcInt(true,queryedge->FromNode->current_nodeid);
attributes[0] = actNodeInt;
attributes[1] = minNodeId;
CompositeKey actNodeLower(attributes,kElems,false);
attributes[1] = maxNodeId;
CompositeKey actNodeUpper(attributes,kElems,true);
orelIt = (OrderedRelationIterator*) orel->MakeRangeScan(actNodeLower, \
actNodeUpper);
Tuple* tuple = orelIt->GetNextTuple();
while (tuple != NULL){
if (!queryedge->Reverse) {
if (((CcInt*)tuple->GetAttribute(1))->GetValue() == toid) {
break;
}
}
else if (queryedge->Reverse) {
if (((CcInt*)tuple->GetAttribute(0))->GetValue() == toid) {
break;
}
}
tuple = orelIt->GetNextTuple();
}
if (tuple != NULL)
{
// check edge type
if ((queryedge->TypeName!="") && (queryedge->TypeName!=ri->Name))
{
LOGOP(30,"PGraphQueryProcessor::CheckEdge","typename failed");
tuple->DeleteIfAllowed();
if (orelIt!=NULL) {
delete orelIt;
orelIt=NULL;
}
if (orel!=NULL){
delete orel;
orel=NULL;
}
return false;
}
// check node filters
if (!MatchesFilters(queryedge, &ri->RelSchema, tuple)) {
tuple->DeleteIfAllowed();
if (orelIt!=NULL) {
delete orelIt;
orelIt=NULL;
}
if (orel!=NULL){
delete orel;
orel=NULL;
}
return false;
}
// check global filters
if (queryedge->Alias!="") {
if (!tree->filterList.Matches(queryedge->Alias, &ri->RelSchema, tuple)) {
tuple->DeleteIfAllowed();
if (orelIt!=NULL) {
delete orelIt;
orelIt=NULL;
}
if (orel!=NULL){
delete orel;
orel=NULL;
}
return false;
}
}
// add alias mapping, if any
if (queryedge->Alias!="") {
aliases[queryedge->Alias]=queryedge;
}
tuple->DeleteIfAllowed();
if (orelIt!=NULL) {
delete orelIt;
orelIt=NULL;
}
if (orel!=NULL){
delete orel;
orel=NULL;
}
return true;
}
if (orelIt!=NULL) {
delete orelIt;
orelIt=NULL;
}
if (orel!=NULL){
delete orel;
orel=NULL;
}
return false;
}
/*
checks if the given QueryNode matches to the filter of the querytree
*/
//----------------------------------------------------------------------------
bool PGraphQueryProcessor::CheckNode(int nodeid, QueryTreeNode *node)
{
LOGOP(30,"PGraphQueryProcessor::CheckNode",nodeid);
RelationInfo* ri = pgraphMem->RelRegistry.GetRelationInfo(
pgraphMem->AdjList.NodeRelIdList[nodeid]);
Tuple *tuple=pgraphMem->AdjList.NodeList[nodeid];
// node type name matches
if ((node->TypeName!="") && (node->TypeName!=ri->Name)) {
LOGOP(30,"Type not expected");
return false;
}
// check node filters
if (!MatchesFilters(node, &ri->RelSchema, tuple)) return false;
// check global filters
if ( node->Alias!="")
if (!tree->filterList.Matches(node->Alias, &ri->RelSchema, tuple))
return false;
// keep nodeid and register alias (once necessary)
node->current_nodeid=nodeid;
// add alias mapping, if any
if (node->Alias!="") {
aliases[node->Alias]=node;
}
return true;
}
/*
checks if the given QueryNode matches to the filter of the querytree
*/
//----------------------------------------------------------------------------
bool PGraphQueryProcessor::CheckNode2(int nodeid, QueryTreeNode *node)
{
LOGOP(30,"PGraphQueryProcessor::CheckNode",nodeid);
RelationInfo* ri = pgraphMem->RelRegistry.GetRelationInfo(node->TypeName);
Word resultword;
bool defined;
SecondoSystem::GetCatalog()->GetObject(node->TypeName, resultword, defined);
OrderedRelation* orel = (OrderedRelation*) resultword.addr;
OrderedRelationIterator* orelIt = 0;
vector<void*> attributes(2);
vector<SmiKey::KeyDataType> kElems(2);
SmiKey test((int32_t) 0);
kElems[0] = test.GetType();
kElems[1] = test.GetType();
CcInt* minNodeId = new CcInt(true,0);
CcInt* maxNodeId = new CcInt(true,numeric_limits<int>::max());
CcInt* actNodeInt = new CcInt(true,nodeid);
attributes[0] = actNodeInt;
attributes[1] = minNodeId;
CompositeKey actNodeLower(attributes,kElems,false);
attributes[1] = maxNodeId;
CompositeKey actNodeUpper(attributes,kElems,true);
orelIt = (OrderedRelationIterator*) orel->MakeRangeScan(actNodeLower, \
actNodeUpper);
Tuple* tuple = orelIt->GetNextTuple();
if (tuple != NULL)
{
// node type name matches
if ((node->TypeName!="") && (node->TypeName!=ri->Name)) {
LOGOP(30,"Type not expected");
tuple->DeleteIfAllowed();
if (orelIt!=NULL) {
delete orelIt;
orelIt=NULL;
}
if (orel!=NULL){
delete orel;
orel=NULL;
}
return false;
}
// check node filters
if (!MatchesFilters(node, &ri->RelSchema, tuple))
{
tuple->DeleteIfAllowed();
if (orelIt!=NULL) {
delete orelIt;
orelIt=NULL;
}
if (orel!=NULL){
delete orel;
orel=NULL;
}
return false;
}
// check global filters
if ( node->Alias!="")
if (!tree->filterList.Matches(node->Alias, &ri->RelSchema, tuple)) {
tuple->DeleteIfAllowed();
if (orelIt!=NULL) {
delete orelIt;
orelIt=NULL;
}
if (orel!=NULL){
delete orel;
orel=NULL;
}
return false;
}
// keep nodeid and register alias (once necessary)
node->current_nodeid=nodeid;
// add alias mapping, if any
if (node->Alias!="") {
aliases[node->Alias]=node;
}
tuple->DeleteIfAllowed();
if (orelIt!=NULL) {
delete orelIt;
orelIt=NULL;
}
if (orel!=NULL){
delete orel;
orel=NULL;
}
return true;
}
if (orelIt!=NULL) {
delete orelIt;
orelIt=NULL;
}
if (orel!=NULL){
delete orel;
orel=NULL;
}
return false;
}
/*
searches for resulttuple with the next node
*/
//----------------------------------------------------------------------------
bool PGraphQueryProcessor::NextNode()
{
LOGOP(30,"PGraphQueryProcessor::NextNode");
bool found=false;
int index=poslist.size()-1;
while (true)
{
// highest entry already processed
if (index<0) break;
//
LOGOP(30,"PGraphQueryProcessor::NextNode","increasing pos ",index);
found = NextEdge(poslist.at(index));
LOGOP(30,"PGraphQueryProcessor::NextNode","pos ",index, "increased: ",
found?"true":"false");
if (found) break;
//
index--;
}
if (found)
{
for(uint i=index+1;i<poslist.size(); i++)
{
LOGOP(30,"PGraphQueryProcessor::NextNode","reset pos ",i);
MatchEdge(poslist.at(i));
}
}
return found;
}
/*
searches for resulttuple with the next node
*/
//----------------------------------------------------------------------------
bool PGraphQueryProcessor::NextNode2()
{
LOGOP(30,"PGraphQueryProcessor::NextNode2");
bool found=false;
int index=poslist.size()-1;
while (true)
{
// highest entry already processed
if (index<0) break;
//
LOGOP(30,"PGraphQueryProcessor::NextNode","increasing pos ",index);
found = NextEdge2(poslist.at(index));
LOGOP(30,"PGraphQueryProcessor::NextNode","pos ",index, "increased: ",
found?"true":"false");
if (found) break;
//
index--;
}
if (found)
{
for(uint i=index+1;i<poslist.size(); i++)
{
LOGOP(30,"PGraphQueryProcessor::NextNode","reset pos ",i);
MatchEdge2(poslist.at(i));
}
}
return found;
}
/*
recursive searching for resulttuple
*/
//----------------------------------------------------------------------------
bool PGraphQueryProcessor::MatchNode(int nodeid, QueryTreeNode *node)
{
LOGOP(30,"PGraphQueryProcessor::MatchNode",nodeid);
// current node already set
//if (node->current_nodeid==nodeid) return true;
//
bool ok=CheckNode(nodeid, node);
if (ok)
{
LOGOP(30,"QueryTreeNode::Match","ok for ",nodeid, "(Type:",node->TypeName,
")","(Alias:",node->Alias,")");
// try to match all edges
for (auto&& queryedge:node->Edges)
{
bool edgefound = MatchEdge(queryedge);
if (!edgefound)
{
LOGOP(30,"QueryTreeNode::Match"," no matching edge found !");
return false;
}
}
// OK
return true;
}
else
{
LOGOP(30,"QueryTreeNode::Match"," node filter failed");
return false;
}
}
/*
recursive searching for resulttuple
*/
//----------------------------------------------------------------------------
bool PGraphQueryProcessor::MatchNode2(int nodeid, QueryTreeNode *node)
{
LOGOP(30,"PGraphQueryProcessor::MatchNode",nodeid);
// current node already set
//if (node->current_nodeid==nodeid) return true;
//
bool ok=CheckNode2(nodeid, node);
if (ok)
{
LOGOP(30,"QueryTreeNode::Match","ok for ",nodeid, "(Type:",node->TypeName,
")","(Alias:",node->Alias,")");
// try to match all edges
for (auto&& queryedge:node->Edges)
{
bool edgefound = MatchEdge2(queryedge);
if (!edgefound)
{
LOGOP(30,"QueryTreeNode::Match"," no matching edge found !");
return false;
}
}
// OK
return true;
}
else
{
LOGOP(30,"QueryTreeNode::Match"," node filter failed");
return false;
}
}
/*
setting the QueryTree
*/
//----------------------------------------------------------------------------
void PGraphQueryProcessor::SetQueryTree(QueryTree *qtree)
{
tree=qtree;
tree->state=QueryTreeMatchStateEnum::NO_FURTHER_MATCH;
LOGOP(30, "PGraphQueryProcessor::SetQueryTree", "tn:",qtree->Root->TypeName,
"alias:",qtree->Root->Alias);
tree->Root->GetPosVector(&poslist);
for (auto&& n:poslist)
{
LOGOP(30, "PGraphQueryProcessor::SetQueryTree", "tn:",n->TypeName,
"alias:",n->Alias);
}
}
/*
continues searching with the actual state
*/
//----------------------------------------------------------------------------
void PGraphQueryProcessor::PrepareQueryTreeNextMatch()
{
LOGOP(30, "PGraphQueryProcessor::PrepareQueryTreeNextMatch");
bool res= NextNode();
if (res)
tree->state=QueryTreeMatchStateEnum::MATCH_AVAILABLE;
else
tree->state=QueryTreeMatchStateEnum::NO_FURTHER_MATCH;
}
/*
continues searching with the actual state
*/
//----------------------------------------------------------------------------
void PGraphQueryProcessor::PrepareQueryTreeNextMatch2()
{
LOGOP(30, "PGraphQueryProcessor::PrepareQueryTreeNextMatch");
bool res= NextNode2();
if (res)
tree->state=QueryTreeMatchStateEnum::MATCH_AVAILABLE;
else
tree->state=QueryTreeMatchStateEnum::NO_FURTHER_MATCH;
}
/*
preparing QueryTree
*/
//----------------------------------------------------------------------------
void PGraphQueryProcessor::PrepareQueryTree(int id)
{
LOGOP(30, "PGraphQueryProcessor::PrepareQueryTree","id:",id);
//
bool res=MatchNode(id, tree->Root);
if (res)
tree->state=QueryTreeMatchStateEnum::MATCH_AVAILABLE;
else
tree->state=QueryTreeMatchStateEnum::NO_FURTHER_MATCH;
}
/*
preparing QueryTree
*/
//----------------------------------------------------------------------------
void PGraphQueryProcessor::PrepareQueryTree2(int id)
{
LOGOP(30, "PGraphQueryProcessor::PrepareQueryTree","id:",id);
//
bool res=MatchNode2(id, tree->Root);
if (res)
tree->state=QueryTreeMatchStateEnum::MATCH_AVAILABLE;
else
tree->state=QueryTreeMatchStateEnum::NO_FURTHER_MATCH;
}
/*
searching for results with the next input Node
*/
//----------------------------------------------------------------------------
void PGraphQueryProcessor::PrepareQueryTreeForNextInputNode()
{
Word rec;
LOGOP(30, "PGraphQueryProcessor::PrepareQueryTreeForNextInputNode");
Tuple *tuple = NULL;
// read from relation
if (_InputRelationIterator!=NULL)
{
tuple = _InputRelationIterator->GetNextTuple();
if (tuple==NULL)
InputStreamState=InputStreamStateEnum::Closed;
}
else
{
// read from stream
qp->Request(_InputStreamAddress, rec);
if ( qp->Received(_InputStreamAddress) )
tuple=((Tuple*)rec.addr);
else
InputStreamState=InputStreamStateEnum::Closed;
}
if (tuple!=NULL)
{
// get global id
RelationInfo *ri=pgraphMem->RelRegistry.GetRelationInfo(tree->Root
->TypeName);
if (ri==NULL)
throw PGraph2Exception("query root node needs a type name!");
CcInt *vi=(CcInt*)tuple->GetAttribute( ri->IdAttrIndex );
int id=ri->IdTranslationTable[vi->GetValue()];
LOGOP(30, "PGraphQueryProcessor::PrepareQueryTreeForNextInputNode",
"Input Node: ",ri->Name," local:",vi->GetValue()," glob: ",id );
PrepareQueryTree(id);
tuple->DeleteIfAllowed();
}
}
/*
searching for results with the next input Node
*/
//----------------------------------------------------------------------------
void PGraphQueryProcessor::PrepareQueryTreeForNextInputNode2()
{
Word rec;
LOGOP(30, "PGraphQueryProcessor::PrepareQueryTreeForNextInputNode");
Tuple *tuple = NULL;
// read from relation
if (_InputRelationIterator!=NULL)
{
tuple = _InputRelationIterator->GetNextTuple();
if (tuple==NULL)
InputStreamState=InputStreamStateEnum::Closed;
}
else
{
// read from stream
qp->Request(_InputStreamAddress, rec);
if ( qp->Received(_InputStreamAddress) )
tuple=((Tuple*)rec.addr);
else
InputStreamState=InputStreamStateEnum::Closed;
}
if (tuple!=NULL)
{
// get global id
RelationInfo *ri=pgraphMem->RelRegistry.GetRelationInfo(tree->Root
->TypeName);
if (ri==NULL)
throw PGraph2Exception("query root node needs a type name!");
CcInt *vi=(CcInt*)tuple->GetAttribute( ri->IdAttrIndex );
int localid=vi->GetValue();
LOGOP(30, "PGraphQueryProcessor::PrepareQueryTreeForNextInputNode",
"Input Node: ",ri->Name," local:",vi->GetValue());
PrepareQueryTree2(localid);
tuple->DeleteIfAllowed();
}
}
/*
Reads the next ResultTuple
*/
//----------------------- -----------------------------------------------------
Tuple *PGraphQueryProcessor::ReadNextResultTuple()
{
Tuple* res=NULL;
LOGOP(30,"PGraphQueryProcessor::ReadNextResultTuple");
if (tree->state==QueryTreeMatchStateEnum::NOT_INITIALIZED)
{
LOGOP(30,"PGraphQueryProcessor::ReadNextResultTuple","NOT INITIALIZED");
return NULL;
}
// current tree hat further match?
if (tree->state==QueryTreeMatchStateEnum::MATCH_AVAILABLE)
{
// try to get next match on existing node
PrepareQueryTreeNextMatch();
}
while (true)
{
if (tree->state==QueryTreeMatchStateEnum::NO_FURTHER_MATCH)
{
// no further start node in input stream
if (InputStreamState==InputStreamStateEnum::Closed)
{
LOGOP(30,"PGraphQueryProcessor::ReadNextResultTuple",
"input stream closed");
return NULL;
}
else
{
LOGOP(30,"PGraphQueryProcessor::ReadNextResultTuple",
"next input node");
// continue with next match on existing node
PrepareQueryTreeForNextInputNode();
}
}
if (tree->state==QueryTreeMatchStateEnum::MATCH_AVAILABLE)
{
break;
}
}
// return tuple
//TODO who releases these tuples
LOGOP(30,"PGraphQueryProcessor::ReadNextResultTuple","creating tuple");
res = new Tuple(_OutputTupleType);
for (auto&& outfield : tree->outputFields.Fields)
{
LOGOP(30,"prop:",outfield->PropertyName);
AttrInfo *ainfo=NULL;
Tuple *aliastuple=NULL;
QueryTreeBase *item= aliases[outfield->NodeAlias];
if (item!=NULL) {
QueryTreeNode* node=dynamic_cast<QueryTreeNode*>(item);
if (node!=NULL) {
aliastuple = pgraphMem->AdjList.NodeList[node->current_nodeid];
//ord: aliastuple = pgraphMem->OrdRel.GetActualTuple(node->TypeName,node->
//current_nodeid);
int relid = pgraphMem->AdjList.NodeRelIdList[node->current_nodeid];
// ord: int relid = pgraphMem->RelRegistry.GetRelationId(node->TypeName);
RelationInfo *relinfo=pgraphMem->RelRegistry.GetRelationInfo(relid);
ainfo=relinfo->RelSchema.GetAttrInfo(outfield->PropertyName);
}
QueryTreeEdge* edge=dynamic_cast<QueryTreeEdge*>(item);
if (edge!=NULL)
{
Edge *edgeinfo = pgraphMem->AdjList.EdgeInfo[edge->current_edgeid];
int relid = edgeinfo->RelId;
// ord: int relid = pgraphMem->RelRegistry.GetRelationId(edge->TypeName);
RelationInfo *relinfo=pgraphMem->RelRegistry.GetRelationInfo(relid);
aliastuple = pgraphMem->AdjList.EdgeList[edgeinfo->EdgeId];
// ord: aliastuple = pgraphMem->OrdRel.GetActualTuple(edge->TypeName, edge->
//current_edgeid);
ainfo=relinfo->RelSchema.GetAttrInfo(outfield->PropertyName);
}
}
if (ainfo!=NULL)
{
if (ainfo->TypeName=="text")
{
res->PutAttribute(outfield->index, new FText( true,
ainfo->GetStringVal(aliastuple) ));
}
if (ainfo->TypeName=="int")
{
res->PutAttribute(outfield->index, new CcInt( true,
std::stoi(ainfo->GetStringVal(aliastuple)) ));
}
if (ainfo->TypeName=="string")
{
res->PutAttribute(outfield->index, new CcString( true,
ainfo->GetStringVal(aliastuple) ));
}
}
else
{
res->PutAttribute(outfield->index, new CcString( true,"???" ));
}
}
LOGOP(30,"/PGraphQueryProcessor::ReadNextResultTuple");
return res;
}
/*
Reads the next ResultTuple
*/
//----------------------- -----------------------------------------------------
Tuple *PGraphQueryProcessor::ReadNextResultTuple2()
{
Tuple* res=NULL;
LOGOP(30,"PGraphQueryProcessor::ReadNextResultTuple");
if (tree->state==QueryTreeMatchStateEnum::NOT_INITIALIZED)
{
LOGOP(30,"PGraphQueryProcessor::ReadNextResultTuple","NOT INITIALIZED");
return NULL;
}
// current tree hat further match?
if (tree->state==QueryTreeMatchStateEnum::MATCH_AVAILABLE)
{
// try to get next match on existing node
PrepareQueryTreeNextMatch2();
}
while (true)
{
if (tree->state==QueryTreeMatchStateEnum::NO_FURTHER_MATCH)
{
// no further start node in input stream
if (InputStreamState==InputStreamStateEnum::Closed)
{
LOGOP(30,"PGraphQueryProcessor::ReadNextResultTuple",
"input stream closed");
return NULL;
}
else
{
LOGOP(30,"PGraphQueryProcessor::ReadNextResultTuple",
"next input node");
// continue with next match on existing node
PrepareQueryTreeForNextInputNode2();
}
}
if (tree->state==QueryTreeMatchStateEnum::MATCH_AVAILABLE)
{
break;
}
}
// return tuple
//TODO who releases these tuples
LOGOP(30,"PGraphQueryProcessor::ReadNextResultTuple","creating tuple");
res = new Tuple(_OutputTupleType);
for (auto&& outfield : tree->outputFields.Fields)
{
LOGOP(30,"prop:",outfield->PropertyName);
AttrInfo *ainfo=NULL;
Tuple *aliastuple=NULL;
QueryTreeBase *item= aliases[outfield->NodeAlias];
OrderedRelationIterator* orelIt = NULL;
OrderedRelation* orel = NULL;
if (item!=NULL) {
QueryTreeNode* node=dynamic_cast<QueryTreeNode*>(item);
if (node!=NULL) {
Word resultword;
bool defined;
SecondoSystem::GetCatalog()->GetObject(node->TypeName, \
resultword, defined);
orel = (OrderedRelation*) resultword.addr;
orelIt = 0;
vector<void*> attributes(2);
vector<SmiKey::KeyDataType> kElems(2);
SmiKey test((int32_t) 0);
kElems[0] = test.GetType();
kElems[1] = test.GetType();
CcInt* minNodeId = new CcInt(true,0);
CcInt* maxNodeId = new CcInt(true,numeric_limits<int>::max());
CcInt* actNodeInt = new CcInt(true,node->current_nodeid);
attributes[0] = actNodeInt;
attributes[1] = minNodeId;
CompositeKey actNodeLower(attributes,kElems,false);
attributes[1] = maxNodeId;
CompositeKey actNodeUpper(attributes,kElems,true);
orelIt = (OrderedRelationIterator*) orel->\
MakeRangeScan(actNodeLower,actNodeUpper);
aliastuple = orelIt->GetNextTuple();
int relid = pgraphMem->RelRegistry.GetRelationId(node->TypeName);
RelationInfo *relinfo=pgraphMem->RelRegistry.GetRelationInfo(relid);
ainfo=relinfo->RelSchema.GetAttrInfo(outfield->PropertyName);
}
QueryTreeEdge* edge=dynamic_cast<QueryTreeEdge*>(item);
if (edge!=NULL)
{
//Edge *edgeinfo = pgraphMem->AdjList.EdgeInfo[edge->current_edgeid];
//int relid = edgeinfo->RelId;
int relid = pgraphMem->RelRegistry.GetRelationId(edge->TypeName);
RelationInfo *relinfo=pgraphMem->RelRegistry.\
GetRelationInfo(relid);
Word resultword;
bool defined;
std::string relname=edge->TypeName;
int toid = edge->current_edge_tonodeid;
if (edge->Reverse) relname = relname+"_B";
SecondoSystem::GetCatalog()->GetObject(relname, \
resultword, defined);
orel = (OrderedRelation*) resultword.addr;
orelIt = 0;
vector<void*> attributes(2);
vector<SmiKey::KeyDataType> kElems(2);
SmiKey test((int32_t) 0);
kElems[0] = test.GetType();
kElems[1] = test.GetType();
CcInt* minNodeId = new CcInt(true,0);
CcInt* maxNodeId = new CcInt(true,numeric_limits<int>::max());
CcInt* actNodeInt = new CcInt(true,edge->current_edgeid);
attributes[0] = actNodeInt;
attributes[1] = minNodeId;
CompositeKey actNodeLower(attributes,kElems,false);
attributes[1] = maxNodeId;
CompositeKey actNodeUpper(attributes,kElems,true);
orelIt = (OrderedRelationIterator*) orel->\
MakeRangeScan(actNodeLower,actNodeUpper);
aliastuple = orelIt->GetNextTuple();
while (aliastuple != NULL){
if (!edge->Reverse) {
if (((CcInt*)aliastuple->GetAttribute(1))->\
GetValue() == toid) {
break;
}
}
else if (edge->Reverse) {
if (((CcInt*)aliastuple->GetAttribute(0))->\
GetValue() == toid) {
break;
}
}
aliastuple = orelIt->GetNextTuple();
}
ainfo=relinfo->RelSchema.GetAttrInfo(outfield->PropertyName);
}
}
if (ainfo!=NULL)
{
if (ainfo->TypeName=="text")
{
res->PutAttribute(outfield->index, new FText( true,
ainfo->GetStringVal(aliastuple) ));
}
if (ainfo->TypeName=="int")
{
res->PutAttribute(outfield->index, new CcInt( true,
std::stoi(ainfo->GetStringVal(aliastuple)) ));
}
if (ainfo->TypeName=="string")
{
res->PutAttribute(outfield->index, new CcString( true,
ainfo->GetStringVal(aliastuple) ));
}
aliastuple->DeleteIfAllowed();
if (orelIt!=NULL) {
delete orelIt;
orelIt=NULL;
}
if (orel!=NULL){
delete orel;
orel=NULL;
}
}
else
{
res->PutAttribute(outfield->index, new CcString( true,"???" ));
}
}
LOGOP(30,"/PGraphQueryProcessor::ReadNextResultTuple");
return res;
}
} // namespace