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/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
|
||||
* for operating on the database. All the functions in
|
||||
@ -253,7 +258,7 @@ class GraphDbAccessor {
|
||||
const GraphDbTypes::Property &property) {
|
||||
const LabelPropertyIndex::Key key(label, property);
|
||||
if (db_.label_property_index_.CreateIndex(key) == false) {
|
||||
throw utils::BasicException(
|
||||
throw IndexExistsException(
|
||||
"Index is either being created by another transaction or already "
|
||||
"exists.");
|
||||
}
|
||||
|
@ -136,7 +136,8 @@ class Interpreter {
|
||||
dynamic_cast<plan::RemoveProperty *>(logical_plan.get()) ||
|
||||
dynamic_cast<plan::RemoveLabels *>(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);
|
||||
auto cursor = logical_plan->MakeCursor(db_accessor);
|
||||
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(CreateIndex &) { return true; }
|
||||
|
||||
} // namespace query::plan
|
||||
|
@ -64,6 +64,7 @@ class CostEstimator : public HierarchicalLogicalOperatorVisitor {
|
||||
bool PostVisit(ExpandUniquenessFilter<EdgeAccessor> &) override;
|
||||
bool PostVisit(Unwind &unwind) override;
|
||||
bool Visit(Once &) override;
|
||||
bool Visit(CreateIndex &) override;
|
||||
|
||||
auto cost() const { return cost_; }
|
||||
auto cardinality() const { return cardinality_; }
|
||||
|
@ -1637,4 +1637,40 @@ void Distinct::DistinctCursor::Reset() {
|
||||
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
|
||||
|
@ -75,6 +75,7 @@ class Merge;
|
||||
class Optional;
|
||||
class Unwind;
|
||||
class Distinct;
|
||||
class CreateIndex;
|
||||
|
||||
using LogicalOperatorCompositeVisitor = ::utils::CompositeVisitor<
|
||||
Once, CreateNode, CreateExpand, ScanAll, ScanAllByLabel, Expand, Filter,
|
||||
@ -83,7 +84,7 @@ using LogicalOperatorCompositeVisitor = ::utils::CompositeVisitor<
|
||||
ExpandUniquenessFilter<EdgeAccessor>, Accumulate, AdvanceCommand, Aggregate,
|
||||
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
|
||||
@ -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 query
|
||||
|
@ -934,3 +934,16 @@ TEST(QueryPlan, RemoveLabelsOnNull) {
|
||||
EXPECT_EQ(0, CountIterable(dba->vertices(false)));
|
||||
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.
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Visit(CreateIndex &op) override {
|
||||
CheckOp(op);
|
||||
return true;
|
||||
}
|
||||
#undef PRE_VISIT
|
||||
|
||||
std::list<BaseOpChecker *> checkers_;
|
||||
|
Loading…
Reference in New Issue
Block a user