|
| 1 | +// Copyright 2024, University of Freiburg, |
| 2 | +// Chair of Algorithms and Data Structures. |
| 3 | +// Author: Julian Mundhahs <[email protected]> |
| 4 | + |
| 5 | +#include "engine/ExecuteUpdate.h" |
| 6 | + |
| 7 | +#include "engine/ExportQueryExecutionTrees.h" |
| 8 | + |
| 9 | +// _____________________________________________________________________________ |
| 10 | +void ExecuteUpdate::executeUpdate( |
| 11 | + const Index& index, const ParsedQuery& query, const QueryExecutionTree& qet, |
| 12 | + DeltaTriples& deltaTriples, const CancellationHandle& cancellationHandle) { |
| 13 | + auto [toInsert, toDelete] = |
| 14 | + computeGraphUpdateQuads(index, query, qet, cancellationHandle); |
| 15 | + |
| 16 | + // "The deletion of the triples happens before the insertion." (SPARQL 1.1 |
| 17 | + // Update 3.1.3) |
| 18 | + deltaTriples.deleteTriples(cancellationHandle, |
| 19 | + std::move(toDelete.idTriples_)); |
| 20 | + deltaTriples.insertTriples(cancellationHandle, |
| 21 | + std::move(toInsert.idTriples_)); |
| 22 | +} |
| 23 | + |
| 24 | +// _____________________________________________________________________________ |
| 25 | +std::pair<std::vector<ExecuteUpdate::TransformedTriple>, LocalVocab> |
| 26 | +ExecuteUpdate::transformTriplesTemplate( |
| 27 | + const Index::Vocab& vocab, const VariableToColumnMap& variableColumns, |
| 28 | + std::vector<SparqlTripleSimpleWithGraph>&& triples) { |
| 29 | + // This LocalVocab only contains IDs that are related to the |
| 30 | + // template. Most of the IDs will be added to the DeltaTriples' LocalVocab. An |
| 31 | + // ID will only not be added if it belongs to a Quad with a variable that has |
| 32 | + // no solutions. |
| 33 | + LocalVocab localVocab{}; |
| 34 | + |
| 35 | + auto transformSparqlTripleComponent = |
| 36 | + [&vocab, &localVocab, |
| 37 | + &variableColumns](TripleComponent component) -> IdOrVariableIndex { |
| 38 | + if (component.isVariable()) { |
| 39 | + AD_CORRECTNESS_CHECK(variableColumns.contains(component.getVariable())); |
| 40 | + return variableColumns.at(component.getVariable()).columnIndex_; |
| 41 | + } else { |
| 42 | + return std::move(component).toValueId(vocab, localVocab); |
| 43 | + } |
| 44 | + }; |
| 45 | + Id defaultGraphIri = [&transformSparqlTripleComponent] { |
| 46 | + IdOrVariableIndex defaultGraph = transformSparqlTripleComponent( |
| 47 | + ad_utility::triple_component::Iri::fromIriref(DEFAULT_GRAPH_IRI)); |
| 48 | + AD_CORRECTNESS_CHECK(std::holds_alternative<Id>(defaultGraph)); |
| 49 | + return std::get<Id>(defaultGraph); |
| 50 | + }(); |
| 51 | + auto transformGraph = |
| 52 | + [&vocab, &localVocab, &defaultGraphIri, |
| 53 | + &variableColumns](SparqlTripleSimpleWithGraph::Graph graph) { |
| 54 | + return std::visit( |
| 55 | + ad_utility::OverloadCallOperator{ |
| 56 | + [&defaultGraphIri](const std::monostate&) -> IdOrVariableIndex { |
| 57 | + return defaultGraphIri; |
| 58 | + }, |
| 59 | + [&vocab, &localVocab](const Iri& iri) -> IdOrVariableIndex { |
| 60 | + ad_utility::triple_component::Iri i = |
| 61 | + ad_utility::triple_component::Iri::fromIriref(iri.iri()); |
| 62 | + return TripleComponent(i).toValueId(vocab, localVocab); |
| 63 | + }, |
| 64 | + [&variableColumns](const Variable& var) -> IdOrVariableIndex { |
| 65 | + AD_CORRECTNESS_CHECK(variableColumns.contains(var)); |
| 66 | + return variableColumns.at(var).columnIndex_; |
| 67 | + }}, |
| 68 | + graph); |
| 69 | + }; |
| 70 | + auto transformSparqlTripleSimple = |
| 71 | + [&transformSparqlTripleComponent, |
| 72 | + &transformGraph](SparqlTripleSimpleWithGraph triple) { |
| 73 | + return std::array{transformSparqlTripleComponent(std::move(triple.s_)), |
| 74 | + transformSparqlTripleComponent(std::move(triple.p_)), |
| 75 | + transformSparqlTripleComponent(std::move(triple.o_)), |
| 76 | + transformGraph(std::move(triple.g_))}; |
| 77 | + }; |
| 78 | + return { |
| 79 | + ad_utility::transform(std::move(triples), transformSparqlTripleSimple), |
| 80 | + std::move(localVocab)}; |
| 81 | +} |
| 82 | + |
| 83 | +// _____________________________________________________________________________ |
| 84 | +std::optional<Id> ExecuteUpdate::resolveVariable(const IdTable& idTable, |
| 85 | + const uint64_t& rowIdx, |
| 86 | + IdOrVariableIndex idOrVar) { |
| 87 | + auto visitId = [](const Id& id) { |
| 88 | + return id.isUndefined() ? std::optional<Id>{} : id; |
| 89 | + }; |
| 90 | + return std::visit( |
| 91 | + ad_utility::OverloadCallOperator{ |
| 92 | + [&idTable, &rowIdx, &visitId](const ColumnIndex& columnInfo) { |
| 93 | + return visitId(idTable(rowIdx, columnInfo)); |
| 94 | + }, |
| 95 | + visitId}, |
| 96 | + idOrVar); |
| 97 | +} |
| 98 | + |
| 99 | +// _____________________________________________________________________________ |
| 100 | +void ExecuteUpdate::computeAndAddQuadsForResultRow( |
| 101 | + const std::vector<TransformedTriple>& templates, |
| 102 | + std::vector<IdTriple<>>& result, const IdTable& idTable, |
| 103 | + const uint64_t rowIdx) { |
| 104 | + for (const auto& [s, p, o, g] : templates) { |
| 105 | + auto subject = resolveVariable(idTable, rowIdx, s); |
| 106 | + auto predicate = resolveVariable(idTable, rowIdx, p); |
| 107 | + auto object = resolveVariable(idTable, rowIdx, o); |
| 108 | + auto graph = resolveVariable(idTable, rowIdx, g); |
| 109 | + |
| 110 | + if (!subject.has_value() || !predicate.has_value() || !object.has_value() || |
| 111 | + !graph.has_value()) { |
| 112 | + continue; |
| 113 | + } |
| 114 | + result.emplace_back(std::array{*subject, *predicate, *object, *graph}); |
| 115 | + } |
| 116 | +} |
| 117 | + |
| 118 | +// _____________________________________________________________________________ |
| 119 | +std::pair<ExecuteUpdate::IdTriplesAndLocalVocab, |
| 120 | + ExecuteUpdate::IdTriplesAndLocalVocab> |
| 121 | +ExecuteUpdate::computeGraphUpdateQuads( |
| 122 | + const Index& index, const ParsedQuery& query, const QueryExecutionTree& qet, |
| 123 | + const CancellationHandle& cancellationHandle) { |
| 124 | + AD_CONTRACT_CHECK(query.hasUpdateClause()); |
| 125 | + auto updateClause = query.updateClause(); |
| 126 | + if (!std::holds_alternative<updateClause::GraphUpdate>(updateClause.op_)) { |
| 127 | + throw std::runtime_error( |
| 128 | + "Only INSERT/DELETE update operations are currently supported."); |
| 129 | + } |
| 130 | + auto graphUpdate = std::get<updateClause::GraphUpdate>(updateClause.op_); |
| 131 | + // Fully materialize the result for now. This makes it easier to execute the |
| 132 | + // update. |
| 133 | + auto result = qet.getResult(false); |
| 134 | + |
| 135 | + const auto& vocab = index.getVocab(); |
| 136 | + |
| 137 | + auto prepareTemplateAndResultContainer = |
| 138 | + [&vocab, &qet, |
| 139 | + &result](std::vector<SparqlTripleSimpleWithGraph>&& tripleTemplates) { |
| 140 | + auto [transformedTripleTemplates, localVocab] = |
| 141 | + transformTriplesTemplate(vocab, qet.getVariableColumns(), |
| 142 | + std::move(tripleTemplates)); |
| 143 | + std::vector<IdTriple<>> updateTriples; |
| 144 | + // The maximum result size is size(query result) x num template rows. |
| 145 | + // The actual result can be smaller if there are template rows with |
| 146 | + // variables for which a result row does not have a value. |
| 147 | + updateTriples.reserve(result->idTable().size() * |
| 148 | + transformedTripleTemplates.size()); |
| 149 | + |
| 150 | + return std::tuple{std::move(transformedTripleTemplates), |
| 151 | + std::move(updateTriples), std::move(localVocab)}; |
| 152 | + }; |
| 153 | + |
| 154 | + auto [toInsertTemplates, toInsert, localVocabInsert] = |
| 155 | + prepareTemplateAndResultContainer(std::move(graphUpdate.toInsert_)); |
| 156 | + auto [toDeleteTemplates, toDelete, localVocabDelete] = |
| 157 | + prepareTemplateAndResultContainer(std::move(graphUpdate.toDelete_)); |
| 158 | + |
| 159 | + uint64_t resultSize = 0; |
| 160 | + for (const auto& [pair, range] : ExportQueryExecutionTrees::getRowIndices( |
| 161 | + query._limitOffset, *result, resultSize)) { |
| 162 | + auto& idTable = pair.idTable_; |
| 163 | + for (const uint64_t i : range) { |
| 164 | + computeAndAddQuadsForResultRow(toInsertTemplates, toInsert, idTable, i); |
| 165 | + cancellationHandle->throwIfCancelled(); |
| 166 | + |
| 167 | + computeAndAddQuadsForResultRow(toDeleteTemplates, toDelete, idTable, i); |
| 168 | + cancellationHandle->throwIfCancelled(); |
| 169 | + } |
| 170 | + } |
| 171 | + |
| 172 | + return { |
| 173 | + IdTriplesAndLocalVocab{std::move(toInsert), std::move(localVocabInsert)}, |
| 174 | + IdTriplesAndLocalVocab{std::move(toDelete), std::move(localVocabDelete)}}; |
| 175 | +} |
0 commit comments