Add CreateIndex operator
Reviewers: florijan, mislav.bradac, buda Reviewed By: florijan, buda Subscribers: pullbot Differential Revision: https://phabricator.memgraph.io/D516
This commit is contained in:
parent
818ac3b731
commit
f5db9d65b0
@ -14,6 +14,11 @@
|
|||||||
#include "storage/edge_accessor.hpp"
|
#include "storage/edge_accessor.hpp"
|
||||||
#include "storage/vertex_accessor.hpp"
|
#include "storage/vertex_accessor.hpp"
|
||||||
|
|
||||||
|
/** Thrown when creating an index which already exists. */
|
||||||
|
class IndexExistsException : public utils::BasicException {
|
||||||
|
using utils::BasicException::BasicException;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An accessor for the database object: exposes functions
|
* An accessor for the database object: exposes functions
|
||||||
* for operating on the database. All the functions in
|
* for operating on the database. All the functions in
|
||||||
@ -253,7 +258,7 @@ class GraphDbAccessor {
|
|||||||
const GraphDbTypes::Property &property) {
|
const GraphDbTypes::Property &property) {
|
||||||
const LabelPropertyIndex::Key key(label, property);
|
const LabelPropertyIndex::Key key(label, property);
|
||||||
if (db_.label_property_index_.CreateIndex(key) == false) {
|
if (db_.label_property_index_.CreateIndex(key) == false) {
|
||||||
throw utils::BasicException(
|
throw IndexExistsException(
|
||||||
"Index is either being created by another transaction or already "
|
"Index is either being created by another transaction or already "
|
||||||
"exists.");
|
"exists.");
|
||||||
}
|
}
|
||||||
|
@ -136,7 +136,8 @@ class Interpreter {
|
|||||||
dynamic_cast<plan::RemoveProperty *>(logical_plan.get()) ||
|
dynamic_cast<plan::RemoveProperty *>(logical_plan.get()) ||
|
||||||
dynamic_cast<plan::RemoveLabels *>(logical_plan.get()) ||
|
dynamic_cast<plan::RemoveLabels *>(logical_plan.get()) ||
|
||||||
dynamic_cast<plan::Delete *>(logical_plan.get()) ||
|
dynamic_cast<plan::Delete *>(logical_plan.get()) ||
|
||||||
dynamic_cast<plan::Merge *>(logical_plan.get())) {
|
dynamic_cast<plan::Merge *>(logical_plan.get()) ||
|
||||||
|
dynamic_cast<plan::CreateIndex *>(logical_plan.get())) {
|
||||||
stream.Header(header);
|
stream.Header(header);
|
||||||
auto cursor = logical_plan->MakeCursor(db_accessor);
|
auto cursor = logical_plan->MakeCursor(db_accessor);
|
||||||
while (cursor->Pull(frame, symbol_table)) continue;
|
while (cursor->Pull(frame, symbol_table)) continue;
|
||||||
|
@ -58,5 +58,6 @@ bool CostEstimator::PostVisit(Unwind &unwind) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool CostEstimator::Visit(Once &) { return true; }
|
bool CostEstimator::Visit(Once &) { return true; }
|
||||||
|
bool CostEstimator::Visit(CreateIndex &) { return true; }
|
||||||
|
|
||||||
} // namespace query::plan
|
} // namespace query::plan
|
||||||
|
@ -64,6 +64,7 @@ class CostEstimator : public HierarchicalLogicalOperatorVisitor {
|
|||||||
bool PostVisit(ExpandUniquenessFilter<EdgeAccessor> &) override;
|
bool PostVisit(ExpandUniquenessFilter<EdgeAccessor> &) override;
|
||||||
bool PostVisit(Unwind &unwind) override;
|
bool PostVisit(Unwind &unwind) override;
|
||||||
bool Visit(Once &) override;
|
bool Visit(Once &) override;
|
||||||
|
bool Visit(CreateIndex &) override;
|
||||||
|
|
||||||
auto cost() const { return cost_; }
|
auto cost() const { return cost_; }
|
||||||
auto cardinality() const { return cardinality_; }
|
auto cardinality() const { return cardinality_; }
|
||||||
|
@ -1637,4 +1637,40 @@ void Distinct::DistinctCursor::Reset() {
|
|||||||
seen_rows_.clear();
|
seen_rows_.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CreateIndex::CreateIndex(GraphDbTypes::Label label,
|
||||||
|
GraphDbTypes::Property property)
|
||||||
|
: label_(label), property_(property) {}
|
||||||
|
|
||||||
|
bool CreateIndex::Accept(HierarchicalLogicalOperatorVisitor &visitor) {
|
||||||
|
return visitor.Visit(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
class CreateIndexCursor : public Cursor {
|
||||||
|
public:
|
||||||
|
CreateIndexCursor(CreateIndex &self, GraphDbAccessor &db)
|
||||||
|
: self_(self), db_(db) {}
|
||||||
|
|
||||||
|
bool Pull(Frame &, const SymbolTable &) override {
|
||||||
|
if (did_create_) return false;
|
||||||
|
try {
|
||||||
|
db_.BuildIndex(self_.label(), self_.property());
|
||||||
|
} catch (const IndexExistsException &) {
|
||||||
|
// Ignore creating an existing index.
|
||||||
|
}
|
||||||
|
did_create_ = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Reset() override { did_create_ = false; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
const CreateIndex &self_;
|
||||||
|
GraphDbAccessor &db_;
|
||||||
|
bool did_create_ = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<Cursor> CreateIndex::MakeCursor(GraphDbAccessor &db) {
|
||||||
|
return std::make_unique<CreateIndexCursor>(*this, db);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace query::plan
|
} // namespace query::plan
|
||||||
|
@ -75,6 +75,7 @@ class Merge;
|
|||||||
class Optional;
|
class Optional;
|
||||||
class Unwind;
|
class Unwind;
|
||||||
class Distinct;
|
class Distinct;
|
||||||
|
class CreateIndex;
|
||||||
|
|
||||||
using LogicalOperatorCompositeVisitor = ::utils::CompositeVisitor<
|
using LogicalOperatorCompositeVisitor = ::utils::CompositeVisitor<
|
||||||
Once, CreateNode, CreateExpand, ScanAll, ScanAllByLabel, Expand, Filter,
|
Once, CreateNode, CreateExpand, ScanAll, ScanAllByLabel, Expand, Filter,
|
||||||
@ -83,7 +84,7 @@ using LogicalOperatorCompositeVisitor = ::utils::CompositeVisitor<
|
|||||||
ExpandUniquenessFilter<EdgeAccessor>, Accumulate, AdvanceCommand, Aggregate,
|
ExpandUniquenessFilter<EdgeAccessor>, Accumulate, AdvanceCommand, Aggregate,
|
||||||
Skip, Limit, OrderBy, Merge, Optional, Unwind, Distinct>;
|
Skip, Limit, OrderBy, Merge, Optional, Unwind, Distinct>;
|
||||||
|
|
||||||
using LogicalOperatorLeafVisitor = ::utils::LeafVisitor<Once>;
|
using LogicalOperatorLeafVisitor = ::utils::LeafVisitor<Once, CreateIndex>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Base class for hierarhical visitors of @c LogicalOperator class
|
* @brief Base class for hierarhical visitors of @c LogicalOperator class
|
||||||
@ -1287,5 +1288,27 @@ class Distinct : public LogicalOperator {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an index for a combination of label and a property.
|
||||||
|
*
|
||||||
|
* This operator takes no input and it shouldn't serve as an input to any
|
||||||
|
* operator. Pulling from the cursor of this operator will create an index in
|
||||||
|
* the database for the vertices which have the given label and property. In
|
||||||
|
* case the index already exists, nothing happens.
|
||||||
|
*/
|
||||||
|
class CreateIndex : public LogicalOperator {
|
||||||
|
public:
|
||||||
|
CreateIndex(GraphDbTypes::Label label, GraphDbTypes::Property property);
|
||||||
|
bool Accept(HierarchicalLogicalOperatorVisitor &visitor) override;
|
||||||
|
std::unique_ptr<Cursor> MakeCursor(GraphDbAccessor &db) override;
|
||||||
|
|
||||||
|
auto label() const { return label_; }
|
||||||
|
auto property() const { return property_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
GraphDbTypes::Label label_;
|
||||||
|
GraphDbTypes::Property property_;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace plan
|
} // namespace plan
|
||||||
} // namespace query
|
} // namespace query
|
||||||
|
@ -934,3 +934,16 @@ TEST(QueryPlan, RemoveLabelsOnNull) {
|
|||||||
EXPECT_EQ(0, CountIterable(dba->vertices(false)));
|
EXPECT_EQ(0, CountIterable(dba->vertices(false)));
|
||||||
EXPECT_EQ(1, PullAll(remove_op, *dba, symbol_table));
|
EXPECT_EQ(1, PullAll(remove_op, *dba, symbol_table));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(QueryPlan, CreateIndex) {
|
||||||
|
// CREATE INDEX ON :label(property)
|
||||||
|
Dbms dbms;
|
||||||
|
auto dba = dbms.active();
|
||||||
|
auto label = dba->label("label");
|
||||||
|
auto property = dba->property("property");
|
||||||
|
EXPECT_FALSE(dba->LabelPropertyIndexExists(label, property));
|
||||||
|
auto create_index = std::make_shared<plan::CreateIndex>(label, property);
|
||||||
|
SymbolTable symbol_table;
|
||||||
|
EXPECT_EQ(PullAll(create_index, *dba, symbol_table), 1);
|
||||||
|
EXPECT_TRUE(dba->LabelPropertyIndexExists(label, property));
|
||||||
|
}
|
||||||
|
@ -82,6 +82,11 @@ class PlanChecker : public HierarchicalLogicalOperatorVisitor {
|
|||||||
// Ignore checking Once, it is implicitly at the end.
|
// Ignore checking Once, it is implicitly at the end.
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Visit(CreateIndex &op) override {
|
||||||
|
CheckOp(op);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
#undef PRE_VISIT
|
#undef PRE_VISIT
|
||||||
|
|
||||||
std::list<BaseOpChecker *> checkers_;
|
std::list<BaseOpChecker *> checkers_;
|
||||||
|
Loading…
Reference in New Issue
Block a user