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:
Teon Banek 2017-07-03 10:38:58 +02:00
parent 818ac3b731
commit f5db9d65b0
8 changed files with 88 additions and 3 deletions

View File

@ -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.");
}

View File

@ -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;

View File

@ -58,5 +58,6 @@ bool CostEstimator::PostVisit(Unwind &unwind) {
}
bool CostEstimator::Visit(Once &) { return true; }
bool CostEstimator::Visit(CreateIndex &) { return true; }
} // namespace query::plan

View File

@ -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_; }

View File

@ -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

View File

@ -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

View File

@ -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));
}

View File

@ -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_;