This is an automated email from the ASF dual-hosted git repository.
twice pushed a commit to branch unstable
in repository https://gitbox.apache.org/repos/asf/kvrocks.git
The following commit(s) were added to refs/heads/unstable by this push:
new 66595db3 Initialize the query plan part of KQIR (#2232)
66595db3 is described below
commit 66595db3f89c3b4738703fe84e8d94ac51cb30e2
Author: Twice <[email protected]>
AuthorDate: Tue Apr 9 20:38:33 2024 +0900
Initialize the query plan part of KQIR (#2232)
---
src/search/ir.h | 21 ++++----
src/search/ir_pass.h | 12 ++---
src/search/ir_plan.h | 113 +++++++++++++++++++++++++++++++++++++++++++
src/search/ir_sema_checker.h | 4 +-
src/search/sql_transformer.h | 16 +++---
5 files changed, 140 insertions(+), 26 deletions(-)
diff --git a/src/search/ir.h b/src/search/ir.h
index 6e3dea28..af64588a 100644
--- a/src/search/ir.h
+++ b/src/search/ir.h
@@ -243,26 +243,26 @@ struct OrExpr : QueryExpr {
NodeIterator ChildEnd() override { return NodeIterator(inners.end()); };
};
-struct Limit : Node {
+struct LimitClause : Node {
size_t offset = 0;
size_t count = std::numeric_limits<size_t>::max();
- Limit(size_t offset, size_t count) : offset(offset), count(count) {}
+ LimitClause(size_t offset, size_t count) : offset(offset), count(count) {}
- std::string_view Name() const override { return "Limit"; }
+ std::string_view Name() const override { return "LimitClause"; }
std::string Dump() const override { return fmt::format("limit {}, {}",
offset, count); }
std::string Content() const override { return fmt::format("{}, {}", offset,
count); }
};
-struct SortBy : Node {
+struct SortByClause : Node {
enum Order { ASC, DESC } order = ASC;
std::unique_ptr<FieldRef> field;
- SortBy(Order order, std::unique_ptr<FieldRef> &&field) : order(order),
field(std::move(field)) {}
+ SortByClause(Order order, std::unique_ptr<FieldRef> &&field) : order(order),
field(std::move(field)) {}
static constexpr const char *OrderToString(Order order) { return order ==
ASC ? "asc" : "desc"; }
- std::string_view Name() const override { return "SortBy"; }
+ std::string_view Name() const override { return "SortByClause"; }
std::string Dump() const override { return fmt::format("sortby {}, {}",
field->Dump(), OrderToString(order)); }
std::string Content() const override { return OrderToString(order); }
@@ -299,11 +299,12 @@ struct SearchStmt : Node {
std::unique_ptr<SelectExpr> select_expr;
std::unique_ptr<IndexRef> index;
std::unique_ptr<QueryExpr> query_expr; // optional
- std::unique_ptr<Limit> limit; // optional
- std::unique_ptr<SortBy> sort_by; // optional
+ std::unique_ptr<LimitClause> limit; // optional
+ std::unique_ptr<SortByClause> sort_by; // optional
- SearchStmt(std::unique_ptr<IndexRef> &&index, std::unique_ptr<QueryExpr>
&&query_expr, std::unique_ptr<Limit> &&limit,
- std::unique_ptr<SortBy> &&sort_by, std::unique_ptr<SelectExpr>
&&select_expr)
+ SearchStmt(std::unique_ptr<IndexRef> &&index, std::unique_ptr<QueryExpr>
&&query_expr,
+ std::unique_ptr<LimitClause> &&limit,
std::unique_ptr<SortByClause> &&sort_by,
+ std::unique_ptr<SelectExpr> &&select_expr)
: select_expr(std::move(select_expr)),
index(std::move(index)),
query_expr(std::move(query_expr)),
diff --git a/src/search/ir_pass.h b/src/search/ir_pass.h
index 9a67530a..a4db9a28 100644
--- a/src/search/ir_pass.h
+++ b/src/search/ir_pass.h
@@ -36,9 +36,9 @@ struct Visitor : Pass {
return Visit(std::move(v));
} else if (auto v = Node::As<IndexRef>(std::move(node))) {
return Visit(std::move(v));
- } else if (auto v = Node::As<Limit>(std::move(node))) {
+ } else if (auto v = Node::As<LimitClause>(std::move(node))) {
return Visit(std::move(v));
- } else if (auto v = Node::As<SortBy>(std::move(node))) {
+ } else if (auto v = Node::As<SortByClause>(std::move(node))) {
return Visit(std::move(v));
} else if (auto v = Node::As<AndExpr>(std::move(node))) {
return Visit(std::move(v));
@@ -77,8 +77,8 @@ struct Visitor : Pass {
node->index = VisitAs<IndexRef>(std::move(node->index));
node->select_expr = VisitAs<SelectExpr>(std::move(node->select_expr));
if (node->query_expr) node->query_expr =
TransformAs<QueryExpr>(std::move(node->query_expr));
- if (node->sort_by) node->sort_by =
VisitAs<SortBy>(std::move(node->sort_by));
- if (node->limit) node->limit = VisitAs<Limit>(std::move(node->limit));
+ if (node->sort_by) node->sort_by =
VisitAs<SortByClause>(std::move(node->sort_by));
+ if (node->limit) node->limit =
VisitAs<LimitClause>(std::move(node->limit));
return node;
}
@@ -133,9 +133,9 @@ struct Visitor : Pass {
return node;
}
- virtual std::unique_ptr<Node> Visit(std::unique_ptr<Limit> node) { return
node; }
+ virtual std::unique_ptr<Node> Visit(std::unique_ptr<LimitClause> node) {
return node; }
- virtual std::unique_ptr<Node> Visit(std::unique_ptr<SortBy> node) {
+ virtual std::unique_ptr<Node> Visit(std::unique_ptr<SortByClause> node) {
node->field = VisitAs<FieldRef>(std::move(node->field));
return node;
}
diff --git a/src/search/ir_plan.h b/src/search/ir_plan.h
new file mode 100644
index 00000000..e718a33a
--- /dev/null
+++ b/src/search/ir_plan.h
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#pragma once
+
+#include <limits>
+#include <memory>
+
+#include "ir.h"
+#include "search/ir_sema_checker.h"
+#include "string_util.h"
+
+namespace kqir {
+
+struct PlanOperator : Node {};
+
+struct FullIndexScan : PlanOperator {
+ IndexInfo *index;
+
+ std::string_view Name() const override { return "FullIndexScan"; };
+ std::string Content() const override { return index->name; };
+ std::string Dump() const override { return fmt::format("full-scan {}",
Content()); }
+};
+
+struct FieldScan : PlanOperator {
+ FieldInfo *field;
+};
+
+struct Interval {
+ double l, r; // [l, r)
+
+ std::string ToString() const { return fmt::format("[{}, {})", l, r); }
+};
+
+struct NumericFieldScan : FieldScan {
+ Interval range;
+
+ std::string_view Name() const override { return "NumericFieldScan"; };
+ std::string Content() const override { return fmt::format("{}, {}",
field->name, range.ToString()); };
+ std::string Dump() const override { return fmt::format("numeric-scan {}",
Content()); }
+};
+
+struct TagFieldScan : FieldScan {
+ std::string tag;
+
+ std::string_view Name() const override { return "TagFieldScan"; };
+ std::string Content() const override { return fmt::format("{}, {}",
field->name, tag); };
+ std::string Dump() const override { return fmt::format("tag-scan {}",
Content()); }
+};
+
+struct Filter : PlanOperator {
+ std::unique_ptr<PlanOperator> source;
+ std::unique_ptr<QueryExpr> filter_expr;
+
+ std::string_view Name() const override { return "Filter"; };
+ std::string Dump() const override { return fmt::format("(filter {}, {})",
source->Dump(), Content()); }
+
+ NodeIterator ChildBegin() override { return {source.get(),
filter_expr.get()}; }
+ NodeIterator ChildEnd() override { return {}; }
+};
+
+struct Merge : PlanOperator {
+ std::vector<std::unique_ptr<PlanOperator>> ops;
+
+ std::string_view Name() const override { return "Merge"; };
+ std::string Dump() const override {
+ return fmt::format("(merge {})", util::StringJoin(ops, [](const auto &v) {
return v->Dump(); }));
+ }
+
+ NodeIterator ChildBegin() override { return NodeIterator(ops.begin()); }
+ NodeIterator ChildEnd() override { return NodeIterator(ops.end()); }
+};
+
+struct Limit : PlanOperator {
+ std::unique_ptr<PlanOperator> op;
+ size_t offset = 0, count = std::numeric_limits<size_t>::max();
+
+ std::string_view Name() const override { return "Limit"; };
+ std::string Dump() const override { return fmt::format("(limit {}, {}: {})",
offset, count, op->Dump()); }
+
+ NodeIterator ChildBegin() override { return NodeIterator{op.get()}; }
+ NodeIterator ChildEnd() override { return {}; }
+};
+
+struct Projection : PlanOperator {
+ std::unique_ptr<PlanOperator> source;
+ std::unique_ptr<SelectExpr> select;
+
+ std::string_view Name() const override { return "Projection"; };
+ std::string Dump() const override { return fmt::format("(project {}: {})",
select, source); }
+
+ NodeIterator ChildBegin() override { return {source.get(), select.get()}; }
+ NodeIterator ChildEnd() override { return {}; }
+};
+
+} // namespace kqir
diff --git a/src/search/ir_sema_checker.h b/src/search/ir_sema_checker.h
index 77427c7c..1660d7f1 100644
--- a/src/search/ir_sema_checker.h
+++ b/src/search/ir_sema_checker.h
@@ -82,9 +82,9 @@ struct SemaChecker {
} else {
return {Status::NotOK, fmt::format("index `{}` not found",
index_name)};
}
- } else if (auto v [[maybe_unused]] = dynamic_cast<Limit *>(node)) {
+ } else if (auto v [[maybe_unused]] = dynamic_cast<LimitClause *>(node)) {
return Status::OK();
- } else if (auto v = dynamic_cast<SortBy *>(node)) {
+ } else if (auto v = dynamic_cast<SortByClause *>(node)) {
if (auto iter = current_index->fields.find(v->field->name); iter ==
current_index->fields.end()) {
return {Status::NotOK, fmt::format("field `{}` not found in index
`{}`", v->field->name, current_index->name)};
} else {
diff --git a/src/search/sql_transformer.h b/src/search/sql_transformer.h
index 63397e40..eb3a1cd0 100644
--- a/src/search/sql_transformer.h
+++ b/src/search/sql_transformer.h
@@ -132,18 +132,18 @@ struct Transformer : ir::TreeTransformer {
count = *ParseInt(node->children[1]->string());
}
- return Node::Create<ir::Limit>(offset, count);
+ return Node::Create<ir::LimitClause>(offset, count);
}
if (Is<OrderByClause>(node)) {
CHECK(node->children.size() == 1 || node->children.size() == 2);
auto field = std::make_unique<FieldRef>(node->children[0]->string());
- auto order = SortBy::Order::ASC;
+ auto order = SortByClause::Order::ASC;
if (node->children.size() == 2 && node->children[1]->string_view() ==
"desc") {
- order = SortBy::Order::DESC;
+ order = SortByClause::Order::DESC;
}
- return Node::Create<SortBy>(order, std::move(field));
+ return Node::Create<SortByClause>(order, std::move(field));
} else if (Is<SearchStmt>(node)) { // root node
CHECK(node->children.size() >= 2 && node->children.size() <= 5);
@@ -151,16 +151,16 @@ struct Transformer : ir::TreeTransformer {
auto select =
Node::MustAs<ir::SelectExpr>(GET_OR_RET(Transform(node->children[0])));
std::unique_ptr<ir::QueryExpr> query_expr;
- std::unique_ptr<ir::Limit> limit;
- std::unique_ptr<ir::SortBy> sort_by;
+ std::unique_ptr<ir::LimitClause> limit;
+ std::unique_ptr<ir::SortByClause> sort_by;
for (size_t i = 2; i < node->children.size(); ++i) {
if (Is<WhereClause>(node->children[i])) {
query_expr =
Node::MustAs<ir::QueryExpr>(GET_OR_RET(Transform(node->children[i])));
} else if (Is<LimitClause>(node->children[i])) {
- limit =
Node::MustAs<ir::Limit>(GET_OR_RET(Transform(node->children[i])));
+ limit =
Node::MustAs<ir::LimitClause>(GET_OR_RET(Transform(node->children[i])));
} else if (Is<OrderByClause>(node->children[i])) {
- sort_by =
Node::MustAs<ir::SortBy>(GET_OR_RET(Transform(node->children[i])));
+ sort_by =
Node::MustAs<ir::SortByClause>(GET_OR_RET(Transform(node->children[i])));
}
}