diff --git a/src/parser/MutateSentences.h b/src/parser/MutateSentences.h index 04f080b546cd14d87cb23dbdc1ff97c81478e687..08cbd02e8ab06891c1b991c407d981bcee315a27 100644 --- a/src/parser/MutateSentences.h +++ b/src/parser/MutateSentences.h @@ -34,52 +34,60 @@ private: std::vector<std::unique_ptr<std::string>> properties_; }; - class VertexTagItem final { - public: - explicit VertexTagItem(std::string *tagName, PropertyList *properties = nullptr) { - tagName_.reset(tagName); - properties_.reset(properties); - } - - std::string toString() const; - - const std::string* tagName() const { - return tagName_.get(); - } - - std::vector<std::string*> properties() const { - if (nullptr == properties_) { - return {}; - } - return properties_->properties(); - } - - private: - std::unique_ptr<std::string> tagName_; - std::unique_ptr<PropertyList> properties_; +public: + explicit VertexTagItem(std::string *tagName, PropertyList *properties = nullptr) { + tagName_.reset(tagName); + properties_.reset(properties); + } + + std::string toString() const; + + const std::string* tagName() const { + return tagName_.get(); + } + + bool isDefaultPropNames() const { + return defaultPropNames_; + } + + void setDefaultPropNames() { + defaultPropNames_ = true; + } + + std::vector<std::string*> properties() const { + if (nullptr == properties_) { + return {}; + } + return properties_->properties(); + } + +private: + bool defaultPropNames_{false}; + std::unique_ptr<std::string> tagName_; + std::unique_ptr<PropertyList> properties_; }; class VertexTagList final { - public: - void addTagItem(VertexTagItem *tagItem) { - tagItems_.emplace_back(tagItem); - } +public: + void addTagItem(VertexTagItem *tagItem) { + tagItems_.emplace_back(tagItem); + } - std::string toString() const; + std::string toString() const; - std::vector<VertexTagItem*> tagItems() const { - std::vector<VertexTagItem*> result; - result.reserve(tagItems_.size()); - for (auto &item : tagItems_) { - result.emplace_back(item.get()); - } - return result; - } + std::vector<VertexTagItem*> tagItems() const { + std::vector<VertexTagItem*> result; + result.reserve(tagItems_.size()); + for (auto &item : tagItems_) { + result.emplace_back(item.get()); + } + return result; + } - private: - std::vector<std::unique_ptr<VertexTagItem>> tagItems_; +private: + std::vector<std::unique_ptr<VertexTagItem>> tagItems_; }; @@ -252,11 +260,11 @@ private: class InsertEdgesSentence final : public Sentence { public: - explicit InsertEdgesSentence(bool ifNotExists) - : Sentence(Kind::kInsertEdges), ifNotExists_(ifNotExists) {} - - void setEdge(std::string *edge) { + explicit InsertEdgesSentence(std::string* edge, EdgeRowList* rows, bool ifNotExists) + : Sentence(Kind::kInsertEdges) { edge_.reset(edge); + rows_.reset(rows); + ifNotExists_ = ifNotExists; } const std::string* edge() const { @@ -274,10 +282,6 @@ public: return properties_->properties(); } - void setRows(EdgeRowList *rows) { - rows_.reset(rows); - } - std::vector<EdgeRowItem*> rows() const { return rows_->rows(); } @@ -286,9 +290,18 @@ public: return ifNotExists_; } + void setDefaultPropNames() { + isDefaultPropNames_ = true; + } + + bool isDefaultPropNames() const { + return isDefaultPropNames_; + } + std::string toString() const override; private: + bool isDefaultPropNames_{false}; bool ifNotExists_{false}; std::unique_ptr<std::string> edge_; std::unique_ptr<PropertyList> properties_; diff --git a/src/parser/parser.yy b/src/parser/parser.yy index 3f2ec9b9b97e180acf1760f5f14202bc1a275356..d475c8535996a8a9f186ae3b758ab88d17726786 100644 --- a/src/parser/parser.yy +++ b/src/parser/parser.yy @@ -2410,7 +2410,11 @@ vertex_tag_list ; vertex_tag_item - : name_label L_PAREN R_PAREN{ + : name_label { + $$ = new VertexTagItem($1); + $$->setDefaultPropNames(); + } + | name_label L_PAREN R_PAREN { $$ = new VertexTagItem($1); } | name_label L_PAREN prop_list R_PAREN { @@ -2467,18 +2471,19 @@ value_list ; insert_edge_sentence - : KW_INSERT KW_EDGE opt_if_not_exists name_label L_PAREN R_PAREN KW_VALUES edge_row_list { - auto sentence = new InsertEdgesSentence($3); - sentence->setEdge($4); + : KW_INSERT KW_EDGE opt_if_not_exists name_label KW_VALUES edge_row_list { + auto sentence = new InsertEdgesSentence($4, $6, $3); + sentence->setDefaultPropNames(); + $$ = sentence; + } + | KW_INSERT KW_EDGE opt_if_not_exists name_label L_PAREN R_PAREN KW_VALUES edge_row_list { + auto sentence = new InsertEdgesSentence($4, $8, $3); sentence->setProps(new PropertyList()); - sentence->setRows($8); $$ = sentence; } | KW_INSERT KW_EDGE opt_if_not_exists name_label L_PAREN prop_list R_PAREN KW_VALUES edge_row_list { - auto sentence = new InsertEdgesSentence($3); - sentence->setEdge($4); + auto sentence = new InsertEdgesSentence($4, $9, $3); sentence->setProps($6); - sentence->setRows($9); $$ = sentence; } ; diff --git a/src/validator/MutateValidator.cpp b/src/validator/MutateValidator.cpp index a4e21e04eabbaaf0f5a76b3f7f66a0dc9f1d8464..7a5c53a9578616512571cdef5bdd79bec7ea530a 100644 --- a/src/validator/MutateValidator.cpp +++ b/src/validator/MutateValidator.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2020 vesoft inc. All rights reserved. +/* Copyright (c) 2021 vesoft inc. All rights reserved. * * This source code is licensed under Apache 2.0 License, * attached with Common Clause Condition 1.0, found in the LICENSES directory. @@ -16,18 +16,9 @@ namespace graph { Status InsertVerticesValidator::validateImpl() { spaceId_ = vctx_->whichSpace().id; - auto status = Status::OK(); - do { - status = check(); - if (!status.ok()) { - break; - } - status = prepareVertices(); - if (!status.ok()) { - break; - } - } while (false); - return status; + NG_RETURN_IF_ERROR(check()); + NG_RETURN_IF_ERROR(prepareVertices()); + return Status::OK(); } Status InsertVerticesValidator::toPlan() { @@ -70,15 +61,23 @@ Status InsertVerticesValidator::check() { } std::vector<std::string> names; - auto props = item->properties(); - // Check prop name is in schema - for (auto *it : props) { - if (schema->getFieldIndex(*it) < 0) { - LOG(ERROR) << "Unknown column `" << *it << "' in schema"; - return Status::SemanticError("Unknown column `%s' in schema", it->c_str()); + if (item->isDefaultPropNames()) { + propSize_ = schema->getNumFields(); + for (size_t i = 0; i < propSize_; ++i) { + const char* propName = schema->getFieldName(i); + names.emplace_back(propName); + } + } else { + auto props = item->properties(); + // Check prop name is in schema + for (auto *it : props) { + if (schema->getFieldIndex(*it) < 0) { + LOG(ERROR) << "Unknown column `" << *it << "' in schema"; + return Status::SemanticError("Unknown column `%s' in schema", it->c_str()); + } + propSize_++; + names.emplace_back(*it); } - propSize_++; - names.emplace_back(*it); } tagPropNames_[tagId] = names; schemas_.emplace_back(tagId, schema); @@ -177,15 +176,22 @@ Status InsertEdgesValidator::check() { return Status::SemanticError("No schema found for `%s'", sentence->edge()->c_str()); } - // Check prop name is in schema - for (auto *it : props) { - if (schema_->getFieldIndex(*it) < 0) { - LOG(ERROR) << "Unknown column `" << *it << "' in schema"; - return Status::SemanticError("Unknown column `%s' in schema", it->c_str()); + if (sentence->isDefaultPropNames()) { + size_t propNums = schema_->getNumFields(); + for (size_t i = 0; i < propNums; ++i) { + const char* propName = schema_->getFieldName(i); + propNames_.emplace_back(propName); + } + } else { + // Check prop name is in schema + for (auto *it : props) { + if (schema_->getFieldIndex(*it) < 0) { + LOG(ERROR) << "Unknown column `" << *it << "' in schema"; + return Status::SemanticError("Unknown column `%s' in schema", it->c_str()); + } + propNames_.emplace_back(*it); } - propNames_.emplace_back(*it); } - return Status::OK(); } diff --git a/tests/tck/features/insert/InsertIfNotExists.feature b/tests/tck/features/insert/InsertIfNotExists.feature index 9b2912d2774fe5520aa97a2379299be8c0125c8d..0e82c53d401a7dd14e8b32010dfcaa9a746663db 100644 --- a/tests/tck/features/insert/InsertIfNotExists.feature +++ b/tests/tck/features/insert/InsertIfNotExists.feature @@ -168,3 +168,112 @@ Feature: Insert vertex and edge with if not exists Then the result should be, in any order: | like._src | like._dst | like._rank | like.likeness | | 'Tom' | 'Peter' | 0 | 83 | + And drop the used space + + Scenario: insert vertex and edge with default propNames + Given an empty graph + And create a space with following options: + | partition_num | 9 | + | replica_factor | 1 | + | vid_type | FIXED_STRING(20) | + And having executed: + """ + CREATE TAG IF NOT EXISTS person(name string, age int); + CREATE EDGE IF NOT EXISTS like(likeness int); + CREATE TAG IF NOT EXISTS student(grade string, number int); + """ + # insert vertex succeeded + When try to execute query: + """ + INSERT VERTEX person(name, age) VALUES "Tom":("Tom", 1) + """ + Then the execution should be successful + When executing query: + """ + INSERT VERTEX person VALUES "Tom":("Tom", 2) + """ + Then the execution should be successful + When executing query: + """ + INSERT VERTEX person() VALUES "Tom":("Tom", 2) + """ + Then a SemanticError should be raised at runtime: Column count doesn't match value count. + When executing query: + """ + INSERT VERTEX person VALUES "Tom":("Tom") + """ + Then a SemanticError should be raised at runtime: Column count doesn't match value count. + When executing query: + """ + INSERT VERTEX person VALUES "Tom":(2, "Tom") + """ + Then a ExecutionError should be raised at runtime: Storage Error: The data type does not meet the requirements. Use the correct type of data. + When executing query: + """ + INSERT VERTEX person VALUES "Tom":("Tom", "2") + """ + Then a ExecutionError should be raised at runtime: Storage Error: The data type does not meet the requirements. Use the correct type of data. + When executing query: + """ + INSERT VERTEX person VALUES "Tom":("Tom", 2, "3") + """ + Then a SemanticError should be raised at runtime: Column count doesn't match value count. + When executing query: + """ + INSERT VERTEX IF NOT EXISTS + person + VALUES + "Conan":("Conan", 10), + "Yao":("Yao", 11), + "Conan":("Conan", 11), + "Tom":("Tom", 3); + """ + Then the execution should be successful + # check vertex result with fetch + When executing query: + """ + FETCH PROP ON person "Tom" YIELD person.age as age + """ + Then the result should be, in any order, with relax comparison: + | VertexID | age | + | "Tom" | 2 | + # check insert edge with default props + When executing query: + """ + INSERT EDGE like(likeness) VALUES "Tom"->"Conan":(100) + """ + Then the execution should be successful + When executing query: + """ + INSERT EDGE like VALUES "Tom"->"Conan":(200) + """ + Then the execution should be successful + When executing query: + """ + INSERT EDGE like VALUES "Tom"->"Conan":("200") + """ + Then a ExecutionError should be raised at runtime: Storage Error: The data type does not meet the requirements. Use the correct type of data. + When executing query: + """ + INSERT EDGE like() VALUES "Tom"->"Conan":(200) + """ + Then a SemanticError should be raised at runtime: Column count doesn't match value count. + When executing query: + """ + INSERT EDGE like VALUES "Tom"->"Conan":(200, 2) + """ + Then a SemanticError should be raised at runtime: Column count doesn't match value count. + When executing query: + """ + INSERT EDGE IF NOT EXISTS like VALUES "Tom"->"Conan":(300) + """ + Then the execution should be successful + # check edge result with fetch + When executing query: + """ + FETCH PROP ON like "Tom"->"Conan" YIELD like.likeness + """ + Then the result should be, in any order: + | like._src | like._dst | like._rank | like.likeness | + | 'Tom' | 'Conan' | 0 | 200 | + And drop the used space