//--------------------------------------------------------------------------- static void collectVariables(const QueryGraph& query,set<unsigned>& vars,const void* except) // Collect all variables used in a query { for (QueryGraph::projection_iterator iter=query.projectionBegin(),limit=query.projectionEnd();iter!=limit;++iter) vars.insert(*iter); if (except!=(&(query.getQuery()))) collectVariables(query.getQuery(),vars,except); }
//--------------------------------------------------------------------------- static void runQuery(Database& db,const string& query,bool explain) // Evaluate a query { QueryGraph queryGraph; { // Parse the query SPARQLLexer lexer(query); SPARQLParser parser(lexer); try { parser.parse(); } catch (const SPARQLParser::ParserException& e) { cerr << "parse error: " << e.message << endl; return; } // And perform the semantic anaylsis try { SemanticAnalysis semana(db); semana.transform(parser,queryGraph); } catch (const SemanticAnalysis::SemanticException& e) { cerr << "semantic error: " << e.message << endl; return; } if (queryGraph.knownEmpty()) { if (explain) cerr << "static analysis determined that the query result will be empty" << endl; else cout << "<empty result>" << endl; return; } } // Run the optimizer PlanGen plangen; Plan* plan=plangen.translate(db,queryGraph); //plan->print(6); if (!plan) { cerr << "internal error plan generation failed" << endl; return; } // Build a physical plan Runtime runtime(db); Operator* operatorTree=CodeGen().translate(runtime,queryGraph,plan,false); // Explain if requested if (explain) { DebugPlanPrinter out(runtime,false); operatorTree->print(out); } else { // Else execute it if (operatorTree->first()) { while (operatorTree->next()) ; } } delete operatorTree; }
//--------------------------------------------------------------------------- static bool isUnused(const QueryGraph& query,const QueryGraph::Node& node,unsigned val) // Check if a variable is unused outside its primary pattern { for (QueryGraph::projection_iterator iter=query.projectionBegin(),limit=query.projectionEnd();iter!=limit;++iter) if ((*iter)==val) return false; return isUnused(query.getQuery(),node,val); }
void SemanticAnalyzer::execute(QueryGraph& queryGraph) { init(); ::Attribute tableAttr; for (Parser::Attribute& attr : result.projections) { analyzeAttribute(attr, "SELECT", tableAttr); } for (auto relation : result.relations) { queryGraph.createNode(relation, database.getTable(relation.relation)); } // Check that all selections are valid for (auto selection : result.selections) { Parser::Attribute& attr = selection.first; Parser::Constant& c = selection.second; ::Attribute tableAttr; analyzeAttribute(attr, "WHERE", tableAttr); if (tableAttr.getType() != c.type) { throw SemanticError("Attribute '" + attr.name + "' and constant '" + c.value + "' do not have the same type (WHERE clause)"); } queryGraph.addSelection(attr, c); } // Check that all joins are valid for (auto joinCondition : result.joinConditions) { Parser::Attribute& attr1 = joinCondition.first; Parser::Attribute& attr2 = joinCondition.second; ::Attribute tableAttr1; ::Attribute tableAttr2; analyzeAttribute(attr1, "WHERE", tableAttr1); analyzeAttribute(attr2, "WHERE", tableAttr2); if (tableAttr1.getType() != tableAttr2.getType()) { throw SemanticError("Attributes '" + attr1.name + "' and '" + attr2.name + "' do not have the same type (WHERE clause"); } queryGraph.createEdge(attr1, attr2, tableAttr1, tableAttr2); } }
//--------------------------------------------------------------------------- static void evalQuery(Database& db,const string& query,bool silent) // Evaluate a query { QueryGraph queryGraph; { // Parse the query SPARQLLexer lexer(query); SPARQLParser parser(lexer); try { parser.parse(); } catch (const SPARQLParser::ParserException& e) { cout << "parse error: " << e.message << endl; return; } // And perform the semantic anaylsis try { SemanticAnalysis semana(db); semana.transform(parser,queryGraph); } catch (const SemanticAnalysis::SemanticException& e) { cout << "semantic error: " << e.message << endl; return; } if (queryGraph.knownEmpty()) { cout << "<empty result>" << endl; return; } } // Run the optimizer PlanGen plangen; Plan* plan=plangen.translate(db,queryGraph); if (!plan) { cout << "plan generation failed" << endl; return; } if (getenv("SHOWCOSTS")) plan->print(0); if (getenv("DISABLESKIPPING")) Operator::disableSkipping=true; // Build a physical plan TemporaryDictionary tempDict(db.getDictionary()); Runtime runtime(db,0,&tempDict); Operator* operatorTree=CodeGen().translate(runtime,queryGraph,plan,silent); if (getenv("SHOWPLAN")) { DebugPlanPrinter out(runtime,false); operatorTree->print(out); } // And execute it Scheduler scheduler; Timestamp start; scheduler.execute(operatorTree); Timestamp stop; cout << "Execution time: " << (stop-start) << " ms" << endl; if (getenv("SHOWCARD")) { DebugPlanPrinter out(runtime,true); operatorTree->print(out); } delete operatorTree; }
//--------------------------------------------------------------------------- static bool evalQuery(Database& db,SPARQLLexer& lexer,ostream& planOut,ostream& statsOut,bool showJoins) // Evaluate a query { QueryGraph queryGraph; std::string::const_iterator queryStart=lexer.getReader(); { // Parse the query SPARQLParser parser(lexer); try { parser.parse(true); } catch (const SPARQLParser::ParserException& e) { cerr << "parse error: " << e.message << endl; return false; } // And perform the semantic anaylsis SemanticAnalysis semana(db); semana.transform(parser,queryGraph); if (queryGraph.knownEmpty()) { cerr << "known empty result ignored" << endl; return true; } } // Run the optimizer PlanGen plangen; Plan* plan=plangen.translate(db,queryGraph); if (!plan) { cerr << "plan generation failed" << endl; return true; } Operator::disableSkipping=true; // Build a physical plan Runtime runtime(db); Operator* operatorTree=CodeGen().translate(runtime,queryGraph,plan,true); Operator* root=dynamic_cast<ResultsPrinter*>(operatorTree)->getInput(); // And execute it Scheduler scheduler; scheduler.execute(root); Timestamp stop; // Write the plan planOut << "# SPARQL Query:" << endl << "# "; std::string::const_iterator queryEnd=lexer.getReader(); for (string::const_iterator iter=queryStart;iter!=queryEnd;++iter) if ((*iter)=='\n') planOut << endl << "# "; else planOut << *iter; planOut << endl << endl << "# Execution plan: <Operator expectedCardinality observedCardinalit [args] [input]>" << endl << endl; { DebugPlanPrinter out(planOut,runtime,true); root->print(out); } // Write the selectivities { if (showJoins) statsOut << "# relations joinVar1 joinVar2 bindings expectedSelectivity observedSelectivity" << endl; else statsOut << "# Stats: {relations} {new predicates(s)} {previous predicate(s)} expectedCardinality observedCardinality expectedSelectivity observedSelectivity" << endl; PredicateCollector out(statsOut,runtime,showJoins); root->print(out); } delete operatorTree; return true; }
//--------------------------------------------------------------------------- void SemanticAnalysis::transform(const SPARQLParser& input,QueryGraph& output) // Perform the transformation { output.clear(); if (!transformSubquery(dict,diffIndex,input.getPatterns(),output.getQuery())) { // A constant could not be resolved. This will produce an empty result output.markAsKnownEmpty(); return; } // Compute the edges output.constructEdges(); // Add the projection entry for (SPARQLParser::projection_iterator iter=input.projectionBegin(),limit=input.projectionEnd();iter!=limit;++iter) output.addProjection(*iter); // Set the duplicate handling switch (input.getProjectionModifier()) { case SPARQLParser::Modifier_None: output.setDuplicateHandling(QueryGraph::AllDuplicates); break; case SPARQLParser::Modifier_Distinct: output.setDuplicateHandling(QueryGraph::NoDuplicates); break; case SPARQLParser::Modifier_Reduced: output.setDuplicateHandling(QueryGraph::ReducedDuplicates); break; case SPARQLParser::Modifier_Count: output.setDuplicateHandling(QueryGraph::CountDuplicates); break; case SPARQLParser::Modifier_Duplicates: output.setDuplicateHandling(QueryGraph::ShowDuplicates); break; } // Order by clause for (SPARQLParser::order_iterator iter=input.orderBegin(),limit=input.orderEnd();iter!=limit;++iter) { QueryGraph::Order o; if (~(*iter).id) { if (!binds(input.getPatterns(),(*iter).id)) continue; o.id=(*iter).id; } else { o.id=~0u; } o.descending=(*iter).descending; output.addOrder(o); } // Set the limit output.setLimit(input.getLimit()); }