Implement plan cloning with LCP

Summary:
Implement proper plan cloning using LCP instead of hacking it with
serialization.

depends on D1815

Reviewers: teon.banek, llugovic

Reviewed By: teon.banek

Subscribers: pullbot

Differential Revision: https://phabricator.memgraph.io/D1816
This commit is contained in:
Marin Tomic 2019-01-21 16:36:58 +01:00
parent 62e06d4b70
commit 914f40411a
7 changed files with 371 additions and 254 deletions

View File

@ -61,33 +61,54 @@ Usage example:
(defun copy-object (source-name dest-name) (defun copy-object (source-name dest-name)
(format nil "~A = ~A;" dest-name source-name)) (format nil "~A = ~A;" dest-name source-name))
;; TODO: This could be a common function in types.lisp if it were improved
;; a bit. It probably won't be necessary once we refactor LCP to use uniform
;; type designators.
(defun get-type (type-designator)
(ctypecase type-designator
(lcp::cpp-type type-designator)
(string (lcp::parse-cpp-type-declaration type-designator))
(symbol (lcp::cpp-type type-designator))))
(defun clone-by-copy-p (object-type) (defun clone-by-copy-p (object-type)
(cond (let ((object-type (get-type object-type)))
((string= "vector" (lcp::cpp-type-name object-type)) (cond
(clone-by-copy-p (car (lcp::cpp-type-type-args object-type)))) ((string= "vector" (lcp::cpp-type-name object-type))
((string= "optional" (lcp::cpp-type-name object-type)) (clone-by-copy-p (car (lcp::cpp-type-type-args object-type))))
(clone-by-copy-p (car (lcp::cpp-type-type-args object-type)))) ((string= "optional" (lcp::cpp-type-name object-type))
((string= "unordered_map" (lcp::cpp-type-name object-type)) (clone-by-copy-p (car (lcp::cpp-type-type-args object-type))))
(and (clone-by-copy-p (first (lcp::cpp-type-type-args object-type))) ((string= "unordered_map" (lcp::cpp-type-name object-type))
(clone-by-copy-p (second (lcp::cpp-type-type-args object-type))))) (and (clone-by-copy-p (first (lcp::cpp-type-type-args object-type)))
((string= "pair" (lcp::cpp-type-name object-type)) (clone-by-copy-p (second (lcp::cpp-type-type-args object-type)))))
(and (clone-by-copy-p (first (lcp::cpp-type-type-args object-type))) ((string= "pair" (lcp::cpp-type-name object-type))
(clone-by-copy-p (second (lcp::cpp-type-type-args object-type))))) (and (clone-by-copy-p (first (lcp::cpp-type-type-args object-type)))
((lcp::cpp-type-type-args object-type) nil) (clone-by-copy-p (second (lcp::cpp-type-type-args object-type)))))
(t (or ((lcp::cpp-type-type-args object-type) nil)
(lcp::find-cpp-enum (lcp::cpp-type-name object-type)) ((or (lcp::find-cpp-enum (lcp::cpp-type-name object-type))
(typep object-type 'lcp::cpp-primitive-type) (typep object-type 'lcp::cpp-primitive-type)
(string= "string" (lcp::cpp-type-name object-type)) (string= "string" (lcp::cpp-type-name object-type))
(not (lcp::find-cpp-class (lcp::cpp-type-name object-type))) ;; TODO: We might want to forbid implicit copying of unknown types once
(not (lcp::cpp-class-clone-opts ;; there's a way to globally mark type as trivially copyable. Now it is
(lcp::find-cpp-class (lcp::cpp-type-name object-type)))))))) ;; too annoying to add (:clone :copy) option everywhere.
(not (lcp::find-cpp-class (lcp::cpp-type-name object-type))))
t)
(t
;; We know now that we're dealing with a C++ class defined in
;; LCP. A class is cloneable by copy only if it doesn't have
;; `Clone` function defined, all of its members are cloneable
;; by copy and it is not a member of inheritance hierarchy.
(let ((cpp-class (lcp::find-cpp-class (lcp::cpp-type-name object-type))))
(assert cpp-class)
(and (not (lcp::cpp-class-clone-opts cpp-class))
(not (lcp::direct-subclasses-of cpp-class))
(not (lcp::cpp-class-super-classes cpp-class))
(every (lambda (member)
(or (eq (lcp::cpp-member-clone member) :copy)
(clone-by-copy-p (lcp::cpp-member-type member))))
(lcp::cpp-class-members cpp-class))))))))
(defun clone-object (object-type source-name dest-name &key args) (defun clone-object (object-type source-name dest-name &key args)
(let ((object-type (let ((object-type (get-type object-type))
(ctypecase object-type
(lcp::cpp-type object-type)
(string (lcp::parse-cpp-type-declaration object-type))
(symbol (lcp::cpp-type object-type))))
(arg-list (format nil "~{~A~^, ~}" (arg-list (format nil "~{~A~^, ~}"
(mapcar (lambda (name-and-type) (mapcar (lambda (name-and-type)
(lcp::cpp-variable-name (first name-and-type))) (lcp::cpp-variable-name (first name-and-type)))
@ -115,9 +136,8 @@ Usage example:
((and (lcp::find-cpp-class (lcp::cpp-type-name object-type)) ((and (lcp::find-cpp-class (lcp::cpp-type-name object-type))
(lcp::cpp-class-clone-opts (lcp::find-cpp-class (lcp::cpp-type-name object-type)))) (lcp::cpp-class-clone-opts (lcp::find-cpp-class (lcp::cpp-type-name object-type))))
(format nil "~A = ~A.Clone(~A);" dest-name source-name arg-list)) (format nil "~A = ~A.Clone(~A);" dest-name source-name arg-list))
(t (t (clone-error "Don't know how to clone object of type ~A"
(format nil "static_assert(false, \"Don't know how to clone object of type ~A\");" (lcp::cpp-type-decl object-type))))))
(lcp::cpp-type-decl object-type))))))
(defun clone-vector (elem-type source-name dest-name &key args) (defun clone-vector (elem-type source-name dest-name &key args)
(with-vars ((loop-counter "i")) (with-vars ((loop-counter "i"))

View File

@ -566,172 +566,190 @@
'lcp.slk:slk-error))) 'lcp.slk:slk-error)))
(deftest "clone" (deftest "clone"
(subtest "no inheritance" (macrolet ((single-member-test (member expected)
(undefine-cpp-types) (let ((class-sym (gensym)))
(let ((tree-class (lcp:define-class tree () `(let ((,class-sym (lcp:define-class my-class ()
((value :int32_t) (,member)
(left "std::unique_ptr<Tree>") (:clone))))
(right "std::unique_ptr<Tree>")) ,(etypecase expected
(:clone :return-type (lambda (typename) (string
(format nil "std::unique_ptr<~A>" typename)) `(is-generated (lcp.clone:clone-function-definition-for-class ,class-sym)
:init-object (lambda (var typename) (format nil "MyClass Clone() const {
(format nil "auto ~A = std::make_unique<~A>();" MyClass object;
var typename))))) ~A
(forest-class (lcp:define-class forest () return object;
((name "std::string") }"
(small-tree "std::unique_ptr<Tree>") ,expected)))
(big-tree "std::unique_ptr<Tree>")) (symbol
(:clone)))) (assert (eq expected 'lcp.clone:clone-error))
(is-generated (lcp.clone:clone-function-definition-for-class tree-class) `(is-error (lcp.clone:clone-function-definition-for-class ,class-sym)
"std::unique_ptr<Tree> Clone() const { ',expected)))))))
(subtest "no inheritance"
(undefine-cpp-types)
(let ((tree-class (lcp:define-class tree ()
((value :int32_t)
(left "std::unique_ptr<Tree>")
(right "std::unique_ptr<Tree>"))
(:clone :return-type (lambda (typename)
(format nil "std::unique_ptr<~A>" typename))
:init-object (lambda (var typename)
(format nil "auto ~A = std::make_unique<~A>();"
var typename)))))
(forest-class (lcp:define-class forest ()
((name "std::string")
(small-tree "std::unique_ptr<Tree>")
(big-tree "std::unique_ptr<Tree>"))
(:clone))))
(is-generated (lcp.clone:clone-function-definition-for-class tree-class)
"std::unique_ptr<Tree> Clone() const {
auto object = std::make_unique<Tree>(); auto object = std::make_unique<Tree>();
object->value_ = value_; object->value_ = value_;
object->left_ = left_ ? left_->Clone() : nullptr; object->left_ = left_ ? left_->Clone() : nullptr;
object->right_ = right_ ? right_->Clone() : nullptr; object->right_ = right_ ? right_->Clone() : nullptr;
return object; return object;
}") }")
(is-generated (lcp.clone:clone-function-definition-for-class forest-class) (is-generated (lcp.clone:clone-function-definition-for-class forest-class)
"Forest Clone() const { "Forest Clone() const {
Forest object; Forest object;
object.name_ = name_; object.name_ = name_;
object.small_tree_ = small_tree_ ? small_tree_->Clone() : nullptr; object.small_tree_ = small_tree_ ? small_tree_->Clone() : nullptr;
object.big_tree_ = big_tree_ ? big_tree_->Clone() : nullptr; object.big_tree_ = big_tree_ ? big_tree_->Clone() : nullptr;
return object; return object;
}"))) }")))
(subtest "single inheritance" (subtest "single inheritance"
(undefine-cpp-types) (undefine-cpp-types)
;; Simple case ;; Simple case
(let ((base-class (lcp:define-class base () (let ((base-class (lcp:define-class base ()
((int-member :int32_t) ((int-member :int32_t)
(string-member "std::string")) (string-member "std::string"))
(:clone))) (:clone)))
(child-class (lcp:define-class child (base) (child-class (lcp:define-class child (base)
((another-int-member :int64_t)) ((another-int-member :int64_t))
(:clone)))) (:clone))))
(is-generated (lcp.clone:clone-function-definition-for-class base-class) (is-generated (lcp.clone:clone-function-definition-for-class base-class)
"virtual std::unique_ptr<Base> Clone() const { "virtual std::unique_ptr<Base> Clone() const {
auto object = std::make_unique<Base>(); auto object = std::make_unique<Base>();
object->int_member_ = int_member_; object->int_member_ = int_member_;
object->string_member_ = string_member_; object->string_member_ = string_member_;
return object; return object;
}") }")
(is-generated (lcp.clone:clone-function-definition-for-class child-class) (is-generated (lcp.clone:clone-function-definition-for-class child-class)
"std::unique_ptr<Base> Clone() const override { "std::unique_ptr<Base> Clone() const override {
auto object = std::make_unique<Child>(); auto object = std::make_unique<Child>();
object->int_member_ = int_member_; object->int_member_ = int_member_;
object->string_member_ = string_member_; object->string_member_ = string_member_;
object->another_int_member_ = another_int_member_; object->another_int_member_ = another_int_member_;
return object; return object;
}")) }"))
(undefine-cpp-types) (undefine-cpp-types)
;; Abstract base class ;; Abstract base class
(let ((base-class (lcp:define-class base () (let ((base-class (lcp:define-class base ()
((int-member :int32_t) ((int-member :int32_t)
(string-member "std::string")) (string-member "std::string"))
(:abstractp t) (:abstractp t)
(:clone))) (:clone)))
(child-class (lcp:define-class child (base) (child-class (lcp:define-class child (base)
((another-int-member :int64_t)) ((another-int-member :int64_t))
(:clone)))) (:clone))))
(is-generated (lcp.clone:clone-function-definition-for-class base-class) (is-generated (lcp.clone:clone-function-definition-for-class base-class)
"virtual std::unique_ptr<Base> Clone() const = 0;") "virtual std::unique_ptr<Base> Clone() const = 0;")
(is-generated (lcp.clone:clone-function-definition-for-class child-class) (is-generated (lcp.clone:clone-function-definition-for-class child-class)
"std::unique_ptr<Base> Clone() const override { "std::unique_ptr<Base> Clone() const override {
auto object = std::make_unique<Child>(); auto object = std::make_unique<Child>();
object->int_member_ = int_member_; object->int_member_ = int_member_;
object->string_member_ = string_member_; object->string_member_ = string_member_;
object->another_int_member_ = another_int_member_; object->another_int_member_ = another_int_member_;
return object; return object;
}")) }"))
(undefine-cpp-types) (undefine-cpp-types)
;; :return-type and :init-object propagation ;; :return-type and :init-object propagation
(let ((base-class (lcp:define-class base () (let ((base-class (lcp:define-class base ()
((int-member :int32_t) ((int-member :int32_t)
(string-member "std::string")) (string-member "std::string"))
(:abstractp t) (:abstractp t)
(:clone :return-type (lambda (typename) (:clone :return-type (lambda (typename)
(format nil "~A*" typename)) (format nil "~A*" typename))
:init-object (lambda (var typename) :init-object (lambda (var typename)
(format nil "~A* ~A = GlobalFactory::Create();" (format nil "~A* ~A = GlobalFactory::Create();"
typename var))))) typename var)))))
(child-class (lcp:define-class child (base) (child-class (lcp:define-class child (base)
((another-int-member :int64_t)) ((another-int-member :int64_t))
(:clone)))) (:clone))))
(is-generated (lcp.clone:clone-function-definition-for-class base-class) (is-generated (lcp.clone:clone-function-definition-for-class base-class)
"virtual Base *Clone() const = 0;") "virtual Base *Clone() const = 0;")
(is-generated (lcp.clone:clone-function-definition-for-class child-class) (is-generated (lcp.clone:clone-function-definition-for-class child-class)
"Child *Clone() const override { "Child *Clone() const override {
Child *object = GlobalFactory::Create(); Child *object = GlobalFactory::Create();
object->int_member_ = int_member_; object->int_member_ = int_member_;
object->string_member_ = string_member_; object->string_member_ = string_member_;
object->another_int_member_ = another_int_member_; object->another_int_member_ = another_int_member_;
return object; return object;
}")) }"))
(undefine-cpp-types) (undefine-cpp-types)
;; inheritance with :ignore-other-base-classes and :base ;; inheritance with :ignore-other-base-classes and :base
(let ((base-class (lcp:define-class base ("utils::TotalOrdering") (let ((base-class (lcp:define-class base ("utils::TotalOrdering")
((int-member :int32_t) ((int-member :int32_t)
(string-member "std::string")) (string-member "std::string"))
(:abstractp t) (:abstractp t)
(:clone :base t (:clone :base t
:return-type (lambda (typename) :return-type (lambda (typename)
(format nil "~A*" typename)) (format nil "~A*" typename))
:init-object (lambda (var typename) :init-object (lambda (var typename)
(format nil "~A* ~A = GlobalFactory::Create();" (format nil "~A* ~A = GlobalFactory::Create();"
typename var))))) typename var)))))
(child-class (lcp:define-class child (base "utils::TotalOrdering" "utils::TotalOrdering") (child-class (lcp:define-class child (base "utils::TotalOrdering" "utils::TotalOrdering")
((another-int-member :int64_t)) ((another-int-member :int64_t))
(:clone :ignore-other-base-classes t)))) (:clone :ignore-other-base-classes t))))
(is-generated (lcp.clone:clone-function-definition-for-class base-class) (is-generated (lcp.clone:clone-function-definition-for-class base-class)
"virtual Base *Clone() const = 0;") "virtual Base *Clone() const = 0;")
(is-generated (lcp.clone:clone-function-definition-for-class child-class) (is-generated (lcp.clone:clone-function-definition-for-class child-class)
"Child *Clone() const override { "Child *Clone() const override {
Child *object = GlobalFactory::Create(); Child *object = GlobalFactory::Create();
object->int_member_ = int_member_; object->int_member_ = int_member_;
object->string_member_ = string_member_; object->string_member_ = string_member_;
object->another_int_member_ = another_int_member_; object->another_int_member_ = another_int_member_;
return object; return object;
}"))) }")))
(subtest "extra args" (subtest "extra args"
(undefine-cpp-types) (undefine-cpp-types)
;; extra arguments are always passed when calling `Clone` function ;; extra arguments are always passed when calling `Clone` function
(let ((expression-class (lcp:define-class expression () (let ((expression-class (lcp:define-class expression ()
((lhs "Expression *") ((lhs "Expression *")
(rhs "Expression *")) (rhs "Expression *"))
(:abstractp t) (:abstractp t)
(:clone :return-type (lambda (typename) (:clone :return-type (lambda (typename)
(format nil "~A*" typename)) (format nil "~A*" typename))
:init-object (lambda (var typename) :init-object (lambda (var typename)
(format nil "~A* ~A = storage->Create<~A>();" (format nil "~A* ~A = storage->Create<~A>();"
typename var typename)) typename var typename))
:args '((storage "ExpressionStorage *"))))) :args '((storage "ExpressionStorage *")))))
(and-class (lcp:define-class and (expression) (and-class (lcp:define-class and (expression)
() ()
(:clone))) (:clone)))
(or-class (lcp:define-class or (expression) (or-class (lcp:define-class or (expression)
() ()
(:clone))) (:clone)))
(filter-class (lcp:define-class filter () (filter-class (lcp:define-class filter ()
((expressions "std::vector<Expression *>")) ((expressions "std::vector<Expression *>"))
(:clone :args '((exp-storage "ExpressionStorage *")))))) (:clone :args '((exp-storage "ExpressionStorage *"))))))
(is-generated (lcp.clone:clone-function-definition-for-class expression-class) (is-generated (lcp.clone:clone-function-definition-for-class expression-class)
"virtual Expression *Clone(ExpressionStorage *storage) const = 0;") "virtual Expression *Clone(ExpressionStorage *storage) const = 0;")
(is-generated (lcp.clone:clone-function-definition-for-class and-class) (is-generated (lcp.clone:clone-function-definition-for-class and-class)
"And *Clone(ExpressionStorage *storage) const override { "And *Clone(ExpressionStorage *storage) const override {
And *object = storage->Create<And>(); And *object = storage->Create<And>();
object->lhs_ = lhs_ ? lhs_->Clone(storage) : nullptr; object->lhs_ = lhs_ ? lhs_->Clone(storage) : nullptr;
object->rhs_ = rhs_ ? rhs_->Clone(storage) : nullptr; object->rhs_ = rhs_ ? rhs_->Clone(storage) : nullptr;
return object; return object;
}") }")
(is-generated (lcp.clone:clone-function-definition-for-class or-class) (is-generated (lcp.clone:clone-function-definition-for-class or-class)
"Or *Clone(ExpressionStorage *storage) const override { "Or *Clone(ExpressionStorage *storage) const override {
Or *object = storage->Create<Or>(); Or *object = storage->Create<Or>();
object->lhs_ = lhs_ ? lhs_->Clone(storage) : nullptr; object->lhs_ = lhs_ ? lhs_->Clone(storage) : nullptr;
object->rhs_ = rhs_ ? rhs_->Clone(storage) : nullptr; object->rhs_ = rhs_ ? rhs_->Clone(storage) : nullptr;
return object; return object;
}") }")
(is-generated (lcp.clone:clone-function-definition-for-class filter-class) (is-generated (lcp.clone:clone-function-definition-for-class filter-class)
"Filter Clone(ExpressionStorage *exp_storage) const { "Filter Clone(ExpressionStorage *exp_storage) const {
Filter object; Filter object;
object.expressions_.resize(expressions_.size()); object.expressions_.resize(expressions_.size());
for (auto i1 = 0; i1 < expressions_.size(); ++i1) { for (auto i1 = 0; i1 < expressions_.size(); ++i1) {
@ -740,59 +758,47 @@
} }
return object; return object;
}"))) }")))
(subtest "unsupported" (subtest "unsupported"
;; multiple inheritance ;; multiple inheritance
(undefine-cpp-types) (undefine-cpp-types)
(lcp:define-class first-base () (lcp:define-class first-base ()
((int-member :int32_t)) ((int-member :int32_t))
(:clone)) (:clone))
(lcp:define-class second-base () (lcp:define-class second-base ()
((private-member :int32_t :scope :private)) ((private-member :int32_t :scope :private))
(:clone)) (:clone))
(let ((child-class (lcp:define-class child (first-base second-base) (let ((child-class (lcp:define-class child (first-base second-base)
((name "std::string")) ((name "std::string"))
(:clone))))
(is-error (lcp.clone:clone-function-definition-for-class child-class)
'lcp.clone:clone-error))
;; template classes
(undefine-cpp-types)
(let ((container-class (lcp:define-class (my-container t-element) ()
((data "TElement *")
(size "size_t")))))
(is-error (lcp.clone:clone-function-definition-for-class container-class)
'lcp.clone:clone-error)))
(subtest "custom clone"
(undefine-cpp-types)
(let ((my-class (lcp:define-class my-class ()
((callback "std::function<void(int, int)>" :clone :copy)
(click-counter :int32_t :clone nil)
(widget "Widget"
:clone (lambda (source dest)
#>cpp
${dest} = WidgetFactory::Create(${source}.type());
cpp<#)))
(:clone)))) (:clone))))
(is-error (lcp.clone:clone-function-definition-for-class child-class) (is-generated (lcp.clone:clone-function-definition-for-class my-class)
'lcp.clone:clone-error)) "MyClass Clone() const {
;; template classes
(undefine-cpp-types)
(let ((container-class (lcp:define-class (my-container t-element) ()
((data "TElement *")
(size "size_t")))))
(is-error (lcp.clone:clone-function-definition-for-class container-class)
'lcp.clone:clone-error)))
(subtest "custom clone"
(undefine-cpp-types)
(let ((my-class (lcp:define-class my-class ()
((callback "std::function<void(int, int)>" :clone :copy)
(click-counter :int32_t :clone nil)
(widget "Widget"
:clone (lambda (source dest)
#>cpp
${dest} = WidgetFactory::Create(${source}.type());
cpp<#)))
(:clone))))
(is-generated (lcp.clone:clone-function-definition-for-class my-class)
"MyClass Clone() const {
MyClass object; MyClass object;
object.callback_ = callback_; object.callback_ = callback_;
object.widget_ = WidgetFactory::Create(widget_.type()); object.widget_ = WidgetFactory::Create(widget_.type());
return object; return object;
}"))) }")))
(subtest "types" (subtest "types"
(undefine-cpp-types) (undefine-cpp-types)
(macrolet ((single-member-test (member expected)
(let ((class-sym (gensym)))
`(let ((,class-sym (lcp:define-class my-class ()
(,member)
(:clone))))
(is-generated (lcp.clone:clone-function-definition-for-class ,class-sym)
(format nil "MyClass Clone() const {
MyClass object;
~A
return object;
}"
,expected))))))
(lcp:define-class klondike () (lcp:define-class klondike ()
() ()
(:clone)) (:clone))
@ -922,8 +928,7 @@
} }
object.member_ = std::make_pair(std::move(first1), std::move(second1)); object.member_ = std::make_pair(std::move(first1), std::move(second1));
}") }"))
)
(subtest "pointers" (subtest "pointers"
(single-member-test (member "Klondike *") (single-member-test (member "Klondike *")
"object.member_ = member_ ? member_->Clone() : nullptr;") "object.member_ = member_ ? member_->Clone() : nullptr;")
@ -939,4 +944,25 @@
(single-member-test (member :int32_t) (single-member-test (member :int32_t)
"object.member_ = member_;") "object.member_ = member_;")
(single-member-test (member :char) (single-member-test (member :char)
"object.member_ = member_;"))))) "object.member_ = member_;")))
(subtest "class copying"
(undefine-cpp-types)
(lcp:define-class non-copyable-class-1 ()
((counter "int32_t *")))
(lcp:define-class cloneable-class ()
((uid :int32_t))
(:clone))
(lcp:define-class copyable-class-1 ()
((counter "int32_t *" :clone :copy)))
(lcp:define-class copyable-class-2 ()
((member :int32_t)))
(single-member-test (member "NonCopyableClass1")
lcp.clone:clone-error)
(single-member-test (member "CloneableClass")
"object.member_ = member_.Clone();")
(single-member-test (member "CopyableClass1")
"object.member_ = member_;")
(single-member-test (member "CopyableClass2")
"object.member_ = member_;")
(single-member-test (member "UnknownClass")
"object.member_ = member_;"))))

View File

@ -332,7 +332,14 @@ class AstStorage {
cpp<# cpp<#
(lcp:define-class tree () (lcp:define-class tree ()
((uid :int32_t :scope :public)) ((uid :int32_t :scope :public
:clone (lambda (source dest)
#>cpp
${dest} = ${source};
// TODO(mtomic): This is a hack. Adopting existing UIDs breaks everything
// because `AstStorage` keeps a counter for generating when `Create` is called.
storage->max_existing_uid_ = std::max(storage->max_existing_uid_, ${source});
cpp<#)))
(:abstractp t) (:abstractp t)
(:public (:public
#>cpp #>cpp

View File

@ -18,18 +18,9 @@ namespace {
std::pair<std::unique_ptr<LogicalOperator>, AstStorage> Clone( std::pair<std::unique_ptr<LogicalOperator>, AstStorage> Clone(
const LogicalOperator &original_plan) { const LogicalOperator &original_plan) {
// TODO: Add a proper Clone method to LogicalOperator AstStorage storage;
::capnp::MallocMessageBuilder message; std::unique_ptr<LogicalOperator> root_copy = original_plan.Clone(&storage);
{ return std::make_pair(std::move(root_copy), std::move(storage));
auto builder = message.initRoot<query::plan::capnp::LogicalOperator>();
LogicalOperator::SaveHelper helper;
Save(original_plan, &builder, &helper);
}
auto reader = message.getRoot<query::plan::capnp::LogicalOperator>();
std::unique_ptr<LogicalOperator> plan_copy;
LogicalOperator::LoadHelper helper;
Load(&plan_copy, reader, &helper);
return std::make_pair(std::move(plan_copy), std::move(helper.ast_storage));
} }
int64_t AddWorkerPlan(DistributedPlan &distributed_plan, int64_t AddWorkerPlan(DistributedPlan &distributed_plan,

View File

@ -84,7 +84,8 @@ time on data transfer. It gives no guarantees on result order.")
input_ = input; input_ = input;
} }
cpp<#) cpp<#)
(:serialize (:slk) (:capnp))) (:serialize (:slk) (:capnp))
(:clone))
(defun slk-load-pull-remote (member) (defun slk-load-pull-remote (member)
#>cpp #>cpp
@ -119,7 +120,16 @@ time on data transfer. It gives no guarantees on result order.")
:slk-save #'slk-save-operator-pointer :slk-save #'slk-save-operator-pointer
:slk-load #'slk-load-pull-remote :slk-load #'slk-load-pull-remote
:capnp-save #'save-operator-pointer :capnp-save #'save-operator-pointer
:capnp-load #'load-pull-remote) :capnp-load #'load-pull-remote
:clone (lambda (source dest)
#>cpp
if (${source}) {
std::shared_ptr<LogicalOperator> tmp = ${source}->Clone(storage);
${dest} = std::static_pointer_cast<PullRemote>(tmp);
} else {
${dest} = nullptr;
}
cpp<#))
(advance-command :bool :initval "false" :scope :public)) (advance-command :bool :initval "false" :scope :public))
(:documentation (:documentation
"Operator used to synchronize stages of plan execution between the master and "Operator used to synchronize stages of plan execution between the master and
@ -164,7 +174,8 @@ Logic of the synchronize operator is:
input_ = input; input_ = input;
} }
cpp<#) cpp<#)
(:serialize (:slk) (:capnp))) (:serialize (:slk) (:capnp))
(:clone))
(lcp:define-class pull-remote-order-by (logical-operator) (lcp:define-class pull-remote-order-by (logical-operator)
((input "std::shared_ptr<LogicalOperator>" :scope :public ((input "std::shared_ptr<LogicalOperator>" :scope :public
@ -209,7 +220,8 @@ by having only one result from each worker.")
input_ = input; input_ = input;
} }
cpp<#) cpp<#)
(:serialize (:slk) (:capnp))) (:serialize (:slk) (:capnp))
(:clone))
(lcp:define-class distributed-expand (logical-operator) (lcp:define-class distributed-expand (logical-operator)
((input "std::shared_ptr<LogicalOperator>" :scope :public ((input "std::shared_ptr<LogicalOperator>" :scope :public
@ -242,7 +254,8 @@ by having only one result from each worker.")
input_ = input; input_ = input;
} }
cpp<#) cpp<#)
(:serialize (:slk) (:capnp))) (:serialize (:slk) (:capnp))
(:clone))
(lcp:define-class distributed-expand-bfs (logical-operator) (lcp:define-class distributed-expand-bfs (logical-operator)
((input "std::shared_ptr<LogicalOperator>" :scope :public ((input "std::shared_ptr<LogicalOperator>" :scope :public
@ -312,7 +325,8 @@ by having only one result from each worker.")
input_ = input; input_ = input;
} }
cpp<#) cpp<#)
(:serialize (:slk) (:capnp))) (:serialize (:slk) (:capnp))
(:clone))
(lcp:define-class distributed-create-node (logical-operator) (lcp:define-class distributed-create-node (logical-operator)
((input "std::shared_ptr<LogicalOperator>" :scope :public ((input "std::shared_ptr<LogicalOperator>" :scope :public
@ -348,7 +362,8 @@ by having only one result from each worker.")
input_ = input; input_ = input;
} }
cpp<#) cpp<#)
(:serialize (:slk) (:capnp))) (:serialize (:slk) (:capnp))
(:clone))
(lcp:define-class distributed-create-expand (logical-operator) (lcp:define-class distributed-create-expand (logical-operator)
((node-info "NodeCreationInfo" :scope :public ((node-info "NodeCreationInfo" :scope :public
@ -395,7 +410,8 @@ by having only one result from each worker.")
input_ = input; input_ = input;
} }
cpp<#) cpp<#)
(:serialize (:slk) (:capnp))) (:serialize (:slk) (:capnp))
(:clone))
(lcp:pop-namespace) ;; plan (lcp:pop-namespace) ;; plan
(lcp:pop-namespace) ;; query (lcp:pop-namespace) ;; query

View File

@ -229,7 +229,9 @@ can serve as inputs to others and thus a sequence of operations is formed.")
:load-args '((helper "query::plan::LogicalOperator::SlkLoadHelper *"))) :load-args '((helper "query::plan::LogicalOperator::SlkLoadHelper *")))
(:capnp :base t (:capnp :base t
:save-args '((helper "LogicalOperator::SaveHelper *")) :save-args '((helper "LogicalOperator::SaveHelper *"))
:load-args '((helper "LogicalOperator::LoadHelper *"))))) :load-args '((helper "LogicalOperator::LoadHelper *"))))
(:clone :args '((storage "AstStorage *"))
:base t))
(defun slk-save-ast-pointer (member) (defun slk-save-ast-pointer (member)
#>cpp #>cpp
@ -371,7 +373,8 @@ and false on every following Pull.")
bool did_pull_{false}; bool did_pull_{false};
}; };
cpp<#) cpp<#)
(:serialize (:slk) (:capnp))) (:serialize (:slk) (:capnp))
(:clone))
(defun slk-save-properties (member) (defun slk-save-properties (member)
#>cpp #>cpp
@ -431,7 +434,8 @@ and false on every following Pull.")
(:serialize (:slk :save-args '((helper "query::plan::LogicalOperator::SaveHelper *")) (:serialize (:slk :save-args '((helper "query::plan::LogicalOperator::SaveHelper *"))
:load-args '((helper "query::plan::LogicalOperator::SlkLoadHelper *"))) :load-args '((helper "query::plan::LogicalOperator::SlkLoadHelper *")))
(:capnp :save-args '((helper "LogicalOperator::SaveHelper *")) (:capnp :save-args '((helper "LogicalOperator::SaveHelper *"))
:load-args '((helper "LogicalOperator::LoadHelper *"))))) :load-args '((helper "LogicalOperator::LoadHelper *"))))
(:clone :args '((storage "AstStorage *"))))
(lcp:define-class create-node (logical-operator) (lcp:define-class create-node (logical-operator)
((input "std::shared_ptr<LogicalOperator>" :scope :public ((input "std::shared_ptr<LogicalOperator>" :scope :public
@ -494,7 +498,8 @@ a preceeding `MATCH`), or multiple nodes (`MATCH ... CREATE` or
const std::unique_ptr<Cursor> input_cursor_; const std::unique_ptr<Cursor> input_cursor_;
}; };
cpp<#) cpp<#)
(:serialize (:slk) (:capnp))) (:serialize (:slk) (:capnp))
(:clone))
(lcp:define-struct edge-creation-info () (lcp:define-struct edge-creation-info ()
((symbol "Symbol") ((symbol "Symbol")
@ -516,7 +521,8 @@ a preceeding `MATCH`), or multiple nodes (`MATCH ... CREATE` or
(:serialize (:slk :save-args '((helper "query::plan::LogicalOperator::SaveHelper *")) (:serialize (:slk :save-args '((helper "query::plan::LogicalOperator::SaveHelper *"))
:load-args '((helper "query::plan::LogicalOperator::SlkLoadHelper *"))) :load-args '((helper "query::plan::LogicalOperator::SlkLoadHelper *")))
(:capnp :save-args '((helper "LogicalOperator::SaveHelper *")) (:capnp :save-args '((helper "LogicalOperator::SaveHelper *"))
:load-args '((helper "LogicalOperator::LoadHelper *"))))) :load-args '((helper "LogicalOperator::LoadHelper *"))))
(:clone :args '((storage "AstStorage *"))))
(lcp:define-class create-expand (logical-operator) (lcp:define-class create-expand (logical-operator)
((node-info "NodeCreationInfo" :scope :public ((node-info "NodeCreationInfo" :scope :public
@ -621,7 +627,8 @@ chained in cases when longer paths need creating.
ExpressionEvaluator &evaluator); ExpressionEvaluator &evaluator);
}; };
cpp<#) cpp<#)
(:serialize (:slk) (:capnp))) (:serialize (:slk) (:capnp))
(:clone))
(lcp:define-class scan-all (logical-operator) (lcp:define-class scan-all (logical-operator)
((input "std::shared_ptr<LogicalOperator>" :scope :public ((input "std::shared_ptr<LogicalOperator>" :scope :public
@ -675,7 +682,8 @@ with a constructor argument.
input_ = input; input_ = input;
} }
cpp<#) cpp<#)
(:serialize (:slk) (:capnp))) (:serialize (:slk) (:capnp))
(:clone))
(lcp:define-class scan-all-by-label (scan-all) (lcp:define-class scan-all-by-label (scan-all)
((label "storage::Label" :scope :public)) ((label "storage::Label" :scope :public))
@ -696,7 +704,8 @@ given label.
std::unique_ptr<Cursor> MakeCursor( std::unique_ptr<Cursor> MakeCursor(
database::GraphDbAccessor &db) const override; database::GraphDbAccessor &db) const override;
cpp<#) cpp<#)
(:serialize (:slk) (:capnp))) (:serialize (:slk) (:capnp))
(:clone))
(defun slk-save-optional-bound (member) (defun slk-save-optional-bound (member)
#>cpp #>cpp
@ -774,20 +783,35 @@ given label.
load-bound) load-bound)
reader member capnp-name))) reader member capnp-name)))
(defun clone-optional-bound (source dest)
#>cpp
if (${source}) {
${dest}.emplace(utils::Bound<Expression *>(
${source}->value()->Clone(storage),
${source}->type()));
} else {
${dest} = std::experimental::nullopt;
}
cpp<#)
(lcp:define-class scan-all-by-label-property-range (scan-all) (lcp:define-class scan-all-by-label-property-range (scan-all)
((label "storage::Label" :scope :public) ((label "storage::Label" :scope :public)
(property "storage::Property" :scope :public) (property "storage::Property" :scope :public)
(property-name "std::string" :scope :public) (property-name "std::string" :scope :public)
(lower-bound "std::experimental::optional<Bound>" :scope :public (lower-bound "std::experimental::optional<Bound>" :scope :public
:capnp-type "Utils.Optional(Utils.Bound(Ast.Tree))"
:slk-save #'slk-save-optional-bound :slk-save #'slk-save-optional-bound
:slk-load #'slk-load-optional-bound :slk-load #'slk-load-optional-bound
:capnp-save #'save-optional-bound :capnp-load #'load-optional-bound) :capnp-save #'save-optional-bound
:capnp-load #'load-optional-bound
:capnp-type "Utils.Optional(Utils.Bound(Ast.Tree))"
:clone #'clone-optional-bound)
(upper-bound "std::experimental::optional<Bound>" :scope :public (upper-bound "std::experimental::optional<Bound>" :scope :public
:slk-save #'slk-save-optional-bound :slk-save #'slk-save-optional-bound
:slk-load #'slk-load-optional-bound :slk-load #'slk-load-optional-bound
:capnp-save #'save-optional-bound :capnp-load #'load-optional-bound :capnp-save #'save-optional-bound
:capnp-type "Utils.Optional(Utils.Bound(Ast.Tree))")) :capnp-load #'load-optional-bound
:capnp-type "Utils.Optional(Utils.Bound(Ast.Tree))"
:clone #'clone-optional-bound))
(:documentation (:documentation
"Behaves like @c ScanAll, but produces only vertices with given label and "Behaves like @c ScanAll, but produces only vertices with given label and
property value which is inside a range (inclusive or exlusive). property value which is inside a range (inclusive or exlusive).
@ -826,7 +850,8 @@ property value which is inside a range (inclusive or exlusive).
std::unique_ptr<Cursor> MakeCursor( std::unique_ptr<Cursor> MakeCursor(
database::GraphDbAccessor &db) const override; database::GraphDbAccessor &db) const override;
cpp<#) cpp<#)
(:serialize (:slk) (:capnp))) (:serialize (:slk) (:capnp))
(:clone))
(lcp:define-class scan-all-by-label-property-value (scan-all) (lcp:define-class scan-all-by-label-property-value (scan-all)
((label "storage::Label" :scope :public) ((label "storage::Label" :scope :public)
@ -868,7 +893,8 @@ property value.
std::unique_ptr<Cursor> MakeCursor( std::unique_ptr<Cursor> MakeCursor(
database::GraphDbAccessor &db) const override; database::GraphDbAccessor &db) const override;
cpp<#) cpp<#)
(:serialize (:slk) (:capnp))) (:serialize (:slk) (:capnp))
(:clone))
(lcp:define-struct expand-common () (lcp:define-struct expand-common ()
( (
@ -989,7 +1015,8 @@ pulled.")
bool InitEdges(Frame &, ExecutionContext &); bool InitEdges(Frame &, ExecutionContext &);
}; };
cpp<#) cpp<#)
(:serialize (:slk) (:capnp))) (:serialize (:slk) (:capnp))
(:clone))
(lcp:define-struct expansion-lambda () (lcp:define-struct expansion-lambda ()
((inner-edge-symbol "Symbol" :documentation "Currently expanded edge symbol.") ((inner-edge-symbol "Symbol" :documentation "Currently expanded edge symbol.")
@ -1028,7 +1055,8 @@ pulled.")
(:capnp (:capnp
:save-args '((saved-ast-uids "std::vector<int32_t> *")) :save-args '((saved-ast-uids "std::vector<int32_t> *"))
:load-args '((ast-storage "AstStorage *") :load-args '((ast-storage "AstStorage *")
(loaded-ast-uids "std::vector<int32_t> *"))))) (loaded-ast-uids "std::vector<int32_t> *"))))
(:clone :args '((storage "AstStorage *"))))
(lcp:define-class expand-variable (logical-operator) (lcp:define-class expand-variable (logical-operator)
((input "std::shared_ptr<LogicalOperator>" :scope :public ((input "std::shared_ptr<LogicalOperator>" :scope :public
@ -1189,7 +1217,8 @@ pulled.")
friend class ExpandVariableCursor; friend class ExpandVariableCursor;
friend class ExpandWeightedShortestPathCursor; friend class ExpandWeightedShortestPathCursor;
cpp<#) cpp<#)
(:serialize (:slk) (:capnp))) (:serialize (:slk) (:capnp))
(:clone))
(lcp:define-class construct-named-path (logical-operator) (lcp:define-class construct-named-path (logical-operator)
((input "std::shared_ptr<LogicalOperator>" :scope :public ((input "std::shared_ptr<LogicalOperator>" :scope :public
@ -1223,7 +1252,8 @@ pulled.")
input_ = input; input_ = input;
} }
cpp<#) cpp<#)
(:serialize (:slk) (:capnp))) (:serialize (:slk) (:capnp))
(:clone))
(lcp:define-class filter (logical-operator) (lcp:define-class filter (logical-operator)
((input "std::shared_ptr<LogicalOperator>" :scope :public ((input "std::shared_ptr<LogicalOperator>" :scope :public
@ -1273,7 +1303,8 @@ a boolean value.")
const std::unique_ptr<Cursor> input_cursor_; const std::unique_ptr<Cursor> input_cursor_;
}; };
cpp<#) cpp<#)
(:serialize (:slk) (:capnp))) (:serialize (:slk) (:capnp))
(:clone))
(lcp:define-class produce (logical-operator) (lcp:define-class produce (logical-operator)
((input "std::shared_ptr<LogicalOperator>" :scope :public ((input "std::shared_ptr<LogicalOperator>" :scope :public
@ -1329,7 +1360,8 @@ RETURN clause) the Produce's pull succeeds exactly once.")
const std::unique_ptr<Cursor> input_cursor_; const std::unique_ptr<Cursor> input_cursor_;
}; };
cpp<#) cpp<#)
(:serialize (:slk) (:capnp))) (:serialize (:slk) (:capnp))
(:clone))
(lcp:define-class delete (logical-operator) (lcp:define-class delete (logical-operator)
((input "std::shared_ptr<LogicalOperator>" :scope :public ((input "std::shared_ptr<LogicalOperator>" :scope :public
@ -1382,7 +1414,8 @@ Has a flag for using DETACH DELETE when deleting vertices.")
const std::unique_ptr<Cursor> input_cursor_; const std::unique_ptr<Cursor> input_cursor_;
}; };
cpp<#) cpp<#)
(:serialize (:slk) (:capnp))) (:serialize (:slk) (:capnp))
(:clone))
(lcp:define-class set-property (logical-operator) (lcp:define-class set-property (logical-operator)
((input "std::shared_ptr<LogicalOperator>" :scope :public ((input "std::shared_ptr<LogicalOperator>" :scope :public
@ -1438,7 +1471,8 @@ can be stored (a TypedValue that can be converted to PropertyValue).")
const std::unique_ptr<Cursor> input_cursor_; const std::unique_ptr<Cursor> input_cursor_;
}; };
cpp<#) cpp<#)
(:serialize (:slk) (:capnp))) (:serialize (:slk) (:capnp))
(:clone))
(lcp:define-class set-properties (logical-operator) (lcp:define-class set-properties (logical-operator)
((input "std::shared_ptr<LogicalOperator>" :scope :public ((input "std::shared_ptr<LogicalOperator>" :scope :public
@ -1511,7 +1545,8 @@ that the old properties are discarded and replaced with new ones.")
void Set(TRecordAccessor &record, const TypedValue &rhs) const; void Set(TRecordAccessor &record, const TypedValue &rhs) const;
}; };
cpp<#) cpp<#)
(:serialize (:slk) (:capnp))) (:serialize (:slk) (:capnp))
(:clone))
(lcp:define-class set-labels (logical-operator) (lcp:define-class set-labels (logical-operator)
((input "std::shared_ptr<LogicalOperator>" :scope :public ((input "std::shared_ptr<LogicalOperator>" :scope :public
@ -1558,7 +1593,8 @@ It does NOT remove labels that are already set on that Vertex.")
const std::unique_ptr<Cursor> input_cursor_; const std::unique_ptr<Cursor> input_cursor_;
}; };
cpp<#) cpp<#)
(:serialize (:slk) (:capnp))) (:serialize (:slk) (:capnp))
(:clone))
(lcp:define-class remove-property (logical-operator) (lcp:define-class remove-property (logical-operator)
((input "std::shared_ptr<LogicalOperator>" :scope :public ((input "std::shared_ptr<LogicalOperator>" :scope :public
@ -1606,7 +1642,8 @@ It does NOT remove labels that are already set on that Vertex.")
const std::unique_ptr<Cursor> input_cursor_; const std::unique_ptr<Cursor> input_cursor_;
}; };
cpp<#) cpp<#)
(:serialize (:slk) (:capnp))) (:serialize (:slk) (:capnp))
(:clone))
(lcp:define-class remove-labels (logical-operator) (lcp:define-class remove-labels (logical-operator)
((input "std::shared_ptr<LogicalOperator>" :scope :public ((input "std::shared_ptr<LogicalOperator>" :scope :public
@ -1653,7 +1690,8 @@ If a label does not exist on a Vertex, nothing happens.")
const std::unique_ptr<Cursor> input_cursor_; const std::unique_ptr<Cursor> input_cursor_;
}; };
cpp<#) cpp<#)
(:serialize (:slk) (:capnp))) (:serialize (:slk) (:capnp))
(:clone))
(lcp:define-class edge-uniqueness-filter (logical-operator) (lcp:define-class edge-uniqueness-filter (logical-operator)
((input "std::shared_ptr<LogicalOperator>" :scope :public ((input "std::shared_ptr<LogicalOperator>" :scope :public
@ -1712,7 +1750,8 @@ edge lists).")
const std::unique_ptr<Cursor> input_cursor_; const std::unique_ptr<Cursor> input_cursor_;
}; };
cpp<#) cpp<#)
(:serialize (:slk) (:capnp))) (:serialize (:slk) (:capnp))
(:clone))
(lcp:define-class accumulate (logical-operator) (lcp:define-class accumulate (logical-operator)
((input "std::shared_ptr<LogicalOperator>" :scope :public ((input "std::shared_ptr<LogicalOperator>" :scope :public
@ -1786,7 +1825,8 @@ has been cached will be reconstructed before Pull returns.
bool pulled_all_input_{false}; bool pulled_all_input_{false};
}; };
cpp<#) cpp<#)
(:serialize (:slk) (:capnp))) (:serialize (:slk) (:capnp))
(:clone))
#>cpp #>cpp
/** /**
@ -1881,7 +1921,8 @@ elements are in an undefined state after aggregation.")
:load-args '((helper "query::plan::LogicalOperator::SlkLoadHelper *"))) :load-args '((helper "query::plan::LogicalOperator::SlkLoadHelper *")))
(:capnp (:capnp
:save-args '((helper "LogicalOperator::SaveHelper *")) :save-args '((helper "LogicalOperator::SaveHelper *"))
:load-args '((helper "LogicalOperator::LoadHelper *"))))) :load-args '((helper "LogicalOperator::LoadHelper *"))))
(:clone :args '((storage "AstStorage *"))))
#>cpp #>cpp
Aggregate() = default; Aggregate() = default;
Aggregate(const std::shared_ptr<LogicalOperator> &input, Aggregate(const std::shared_ptr<LogicalOperator> &input,
@ -1981,7 +2022,8 @@ elements are in an undefined state after aggregation.")
void EnsureOkForAvgSum(const TypedValue &value) const; void EnsureOkForAvgSum(const TypedValue &value) const;
}; };
cpp<#) cpp<#)
(:serialize (:slk) (:capnp))) (:serialize (:slk) (:capnp))
(:clone))
(lcp:define-class skip (logical-operator) (lcp:define-class skip (logical-operator)
((input "std::shared_ptr<LogicalOperator>" :scope :public ((input "std::shared_ptr<LogicalOperator>" :scope :public
@ -2041,7 +2083,8 @@ operator's implementation does not expect this.")
int skipped_{0}; int skipped_{0};
}; };
cpp<#) cpp<#)
(:serialize (:slk) (:capnp))) (:serialize (:slk) (:capnp))
(:clone))
(lcp:define-class limit (logical-operator) (lcp:define-class limit (logical-operator)
((input "std::shared_ptr<LogicalOperator>" :scope :public ((input "std::shared_ptr<LogicalOperator>" :scope :public
@ -2104,7 +2147,8 @@ input should be performed).")
int pulled_{0}; int pulled_{0};
}; };
cpp<#) cpp<#)
(:serialize (:slk) (:capnp))) (:serialize (:slk) (:capnp))
(:clone))
(lcp:define-class order-by (logical-operator) (lcp:define-class order-by (logical-operator)
((input "std::shared_ptr<LogicalOperator>" :scope :public ((input "std::shared_ptr<LogicalOperator>" :scope :public
@ -2176,7 +2220,8 @@ are valid for usage after the OrderBy operator.")
decltype(cache_.begin()) cache_it_ = cache_.begin(); decltype(cache_.begin()) cache_it_ = cache_.begin();
}; };
cpp<#) cpp<#)
(:serialize (:slk) (:capnp))) (:serialize (:slk) (:capnp))
(:clone))
(lcp:define-class merge (logical-operator) (lcp:define-class merge (logical-operator)
((input "std::shared_ptr<LogicalOperator>" :scope :public ((input "std::shared_ptr<LogicalOperator>" :scope :public
@ -2249,7 +2294,8 @@ documentation.")
bool pull_input_{true}; bool pull_input_{true};
}; };
cpp<#) cpp<#)
(:serialize (:slk) (:capnp))) (:serialize (:slk) (:capnp))
(:clone))
(lcp:define-class optional (logical-operator) (lcp:define-class optional (logical-operator)
((input "std::shared_ptr<LogicalOperator>" :scope :public ((input "std::shared_ptr<LogicalOperator>" :scope :public
@ -2311,7 +2357,8 @@ and returns true, once.")
bool pull_input_{true}; bool pull_input_{true};
}; };
cpp<#) cpp<#)
(:serialize (:slk) (:capnp))) (:serialize (:slk) (:capnp))
(:clone))
(lcp:define-class unwind (logical-operator) (lcp:define-class unwind (logical-operator)
((input "std::shared_ptr<LogicalOperator>" :scope :public ((input "std::shared_ptr<LogicalOperator>" :scope :public
@ -2368,7 +2415,8 @@ Input is optional (unwind can be the first clause in a query).")
std::vector<TypedValue>::iterator input_value_it_ = input_value_.end(); std::vector<TypedValue>::iterator input_value_it_ = input_value_.end();
}; };
cpp<#) cpp<#)
(:serialize (:slk) (:capnp))) (:serialize (:slk) (:capnp))
(:clone))
(lcp:define-class distinct (logical-operator) (lcp:define-class distinct (logical-operator)
((input "std::shared_ptr<LogicalOperator>" :scope :public ((input "std::shared_ptr<LogicalOperator>" :scope :public
@ -2427,7 +2475,8 @@ This implementation maintains input ordering.")
seen_rows_; seen_rows_;
}; };
cpp<#) cpp<#)
(:serialize (:slk) (:capnp))) (:serialize (:slk) (:capnp))
(:clone))
(lcp:define-class union (logical-operator) (lcp:define-class union (logical-operator)
((left-op "std::shared_ptr<LogicalOperator>" :scope :public ((left-op "std::shared_ptr<LogicalOperator>" :scope :public
@ -2488,7 +2537,8 @@ of symbols used by each of the inputs.")
const std::unique_ptr<Cursor> left_cursor_, right_cursor_; const std::unique_ptr<Cursor> left_cursor_, right_cursor_;
}; };
cpp<#) cpp<#)
(:serialize (:slk) (:capnp))) (:serialize (:slk) (:capnp))
(:clone))
;; TODO: We should probably output this operator in regular planner, not just ;; TODO: We should probably output this operator in regular planner, not just
;; distributed planner. ;; distributed planner.
@ -2533,12 +2583,13 @@ of symbols used by each of the inputs.")
std::shared_ptr<LogicalOperator> input() const override; std::shared_ptr<LogicalOperator> input() const override;
void set_input(std::shared_ptr<LogicalOperator>) override; void set_input(std::shared_ptr<LogicalOperator>) override;
cpp<#) cpp<#)
(:serialize (:slk) (:capnp))) (:serialize (:slk) (:capnp))
(:clone))
(lcp:define-class output-table (logical-operator) (lcp:define-class output-table (logical-operator)
((output-symbols "std::vector<Symbol>" :scope :public :dont-save t) ((output-symbols "std::vector<Symbol>" :scope :public :dont-save t)
(callback "std::function<std::vector<std::vector<TypedValue>>(Frame *, ExecutionContext *)>" (callback "std::function<std::vector<std::vector<TypedValue>>(Frame *, ExecutionContext *)>"
:scope :public :dont-save t)) :scope :public :dont-save t :clone :copy))
(:documentation "An operator that outputs a table, producing a single row on each pull") (:documentation "An operator that outputs a table, producing a single row on each pull")
(:public (:public
#>cpp #>cpp
@ -2567,7 +2618,8 @@ of symbols used by each of the inputs.")
std::shared_ptr<LogicalOperator> input() const override; std::shared_ptr<LogicalOperator> input() const override;
void set_input(std::shared_ptr<LogicalOperator> input) override; void set_input(std::shared_ptr<LogicalOperator> input) override;
cpp<#) cpp<#)
(:serialize (:slk) (:capnp))) (:serialize (:slk) (:capnp))
(:clone))
(lcp:pop-namespace) ;; plan (lcp:pop-namespace) ;; plan
(lcp:pop-namespace) ;; query (lcp:pop-namespace) ;; query

View File

@ -127,6 +127,11 @@ class Yield : public query::plan::LogicalOperator {
LOG(FATAL) << "Please go away, visitor!"; LOG(FATAL) << "Please go away, visitor!";
} }
std::unique_ptr<LogicalOperator> Clone(
query::AstStorage *storage) const override {
LOG(FATAL) << "Don't clone Yield operator!";
}
std::shared_ptr<query::plan::LogicalOperator> input_; std::shared_ptr<query::plan::LogicalOperator> input_;
std::vector<query::Symbol> modified_symbols_; std::vector<query::Symbol> modified_symbols_;
std::vector<std::vector<query::TypedValue>> values_; std::vector<std::vector<query::TypedValue>> values_;