Skip to content
This repository has been archived by the owner on Dec 1, 2022. It is now read-only.

Cherrypick #901 #919 #922 #932 #849 #931

Merged
merged 5 commits into from
Apr 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
- ubuntu1604
- ubuntu1804
- ubuntu2004
- centos6
# - centos6
- centos7
- centos8
container:
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ jobs:
-DENABLE_TESTING=on \
-DENABLE_BUILD_STORAGE=on \
-B build
echo "::set-output name=j::8"
echo "::set-output name=j::10"
;;
ubuntu1804)
# build with Debug type
Expand All @@ -105,7 +105,7 @@ jobs:
-DENABLE_TESTING=on \
-DENABLE_BUILD_STORAGE=on \
-B build
echo "::set-output name=j::8"
echo "::set-output name=j::10"
;;
esac
;;
Expand All @@ -119,7 +119,7 @@ jobs:
-DENABLE_TESTING=on \
-DENABLE_BUILD_STORAGE=on \
-B build
echo "::set-output name=j::4"
echo "::set-output name=j::6"
;;
esac
- name: Make graph
Expand Down
10 changes: 9 additions & 1 deletion src/context/Iterator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,15 @@ void GetNeighborsIter::next() {
}

if (noEdge_) {
currentRow_++;
if (++currentRow_ < rowsUpperBound_) {
return;
}

// go to next dataset
if (++currentDs_ < dsIndices_.end()) {
currentRow_ = currentDs_->ds->begin();
rowsUpperBound_ = currentDs_->ds->end();
}
return;
}

Expand Down
67 changes: 67 additions & 0 deletions src/context/test/IteratorTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,73 @@ TEST(IteratorTest, Sequential) {
}
}

TEST(IteratorTest, GetNeighborNoEdge) {
DataSet ds1;
ds1.colNames = {kVid, "_stats", "_tag:tag1:prop1:prop2", "_expr"};
for (auto i = 0; i < 10; ++i) {
Row row;
// _vid
row.values.emplace_back(folly::to<std::string>(i));
// _stats = empty
row.values.emplace_back(Value());
// tag
List tag;
tag.values.emplace_back(0);
tag.values.emplace_back(1);
row.values.emplace_back(Value(tag));
// _expr = empty
row.values.emplace_back(Value());
ds1.rows.emplace_back(std::move(row));
}

DataSet ds2;
ds2.colNames = {kVid, "_stats", "_tag:tag2:prop1:prop2", "_expr"};
for (auto i = 10; i < 20; ++i) {
Row row;
// _vid
row.values.emplace_back(folly::to<std::string>(i));
// _stats = empty
row.values.emplace_back(Value());
// tag
List tag;
tag.values.emplace_back(0);
tag.values.emplace_back(1);
row.values.emplace_back(Value(tag));
// _expr = empty
row.values.emplace_back(Value());
ds2.rows.emplace_back(std::move(row));
}

List datasets;
datasets.values.emplace_back(std::move(ds1));
datasets.values.emplace_back(std::move(ds2));
auto val = std::make_shared<Value>(std::move(datasets));

{
GetNeighborsIter iter(val);
std::vector<Value> expected = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
"10", "11", "12", "13", "14", "15", "16", "17", "18", "19"};
std::vector<Value> result;
for (; iter.valid(); iter.next()) {
result.emplace_back(iter.getColumn(kVid));
}
EXPECT_EQ(expected, result);
}

{
GetNeighborsIter iter(val);
std::vector<Value> expected;
expected.insert(expected.end(), 10, 0);
expected.insert(expected.end(), 10, Value());
std::vector<Value> result;
for (; iter.valid(); iter.next()) {
result.emplace_back(iter.getTagProp("tag1", "prop1"));
}
EXPECT_EQ(result.size(), 20);
EXPECT_EQ(expected, result);
}
}

TEST(IteratorTest, GetNeighbor) {
DataSet ds1;
ds1.colNames = {kVid,
Expand Down
26 changes: 26 additions & 0 deletions src/executor/query/AggregateExecutor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,32 @@ folly::Future<Status> AggregateExecutor::execute() {
QueryExpressionContext ctx(ectx_);

std::unordered_map<List, std::vector<std::unique_ptr<AggData>>, std::hash<nebula::List>> result;

// generate default result when input dataset is empty
if (UNLIKELY(!iter->valid())) {
List defaultValues;
bool allAggItems = true;
for (size_t i = 0; i < groupItems.size(); ++i) {
auto* item = groupItems[i];
if (UNLIKELY(item->kind() != Expression::Kind::kAggregate)) {
allAggItems = false;
break;
}
AggData aggData;
static_cast<AggregateExpression*>(item)->apply(&aggData, Value::kNullValue);
defaultValues.emplace_back(aggData.result());
}
if (allAggItems) {
List dummyKey;
std::vector<std::unique_ptr<AggData>> cols;
for (size_t i = 0; i < groupItems.size(); ++i) {
cols.emplace_back(new AggData());
cols[i]->setResult(defaultValues[i]);
}
result.emplace(std::make_pair(dummyKey, std::move(cols)));
}
}

for (; iter->valid(); iter->next()) {
List list;
for (auto* key : groupKeys) {
Expand Down
16 changes: 8 additions & 8 deletions src/executor/test/AggregateTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -793,14 +793,14 @@ TEST_F(AggregateTest, Sum) {
// --------
DataSet expected;
expected.colNames = {"sum"};
Row rowNull;
rowNull.values.emplace_back(0);
expected.rows.emplace_back(std::move(rowNull));
for (auto i = 0; i < 5; ++i) {
Row row;
row.values.emplace_back(2 * i);
expected.rows.emplace_back(std::move(row));
}
Row row;
row.values.emplace_back(Value::kNullValue);
expected.rows.emplace_back(std::move(row));

// key = col2
// items = sum(col2)
Expand Down Expand Up @@ -832,7 +832,7 @@ TEST_F(AggregateTest, Sum) {
}
Row row;
row.values.emplace_back(Value::kNullValue);
row.values.emplace_back(Value::kNullValue);
row.values.emplace_back(0);
expected.rows.emplace_back(std::move(row));

// key = col2, col3
Expand Down Expand Up @@ -889,14 +889,14 @@ TEST_F(AggregateTest, Sum) {
// --------
DataSet expected;
expected.colNames = {"sum"};
Row rowNull;
rowNull.values.emplace_back(0);
expected.rows.emplace_back(std::move(rowNull));
for (auto i = 0; i < 5; ++i) {
Row row;
row.values.emplace_back(i);
expected.rows.emplace_back(std::move(row));
}
Row row;
row.values.emplace_back(Value::kNullValue);
expected.rows.emplace_back(std::move(row));

// key = col2
// items = sum(distinct col2)
Expand Down Expand Up @@ -928,7 +928,7 @@ TEST_F(AggregateTest, Sum) {
}
Row row;
row.values.emplace_back(Value::kNullValue);
row.values.emplace_back(Value::kNullValue);
row.values.emplace_back(0);
expected.rows.emplace_back(std::move(row));

// key = col2, col3
Expand Down
17 changes: 15 additions & 2 deletions src/parser/parser.yy
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

#include "common/expression/ReduceExpression.h"
#include "util/ParserUtil.h"
#include "util/ExpressionUtils.h"
#include "context/QueryContext.h"
#include "util/SchemaUtil.h"

Expand Down Expand Up @@ -1286,10 +1287,22 @@ with_clause

match_clause
: KW_MATCH match_path where_clause {
$$ = new MatchClause($2, $3, false/*optinal*/);
if ($3 && graph::ExpressionUtils::findAny($3->filter(),{Expression::Kind::kAggregate})) {
delete($2);
delete($3);
throw nebula::GraphParser::syntax_error(@3, "Invalid use of aggregating function in this context.");
} else {
$$ = new MatchClause($2, $3, false/*optinal*/);
}
}
| KW_OPTIONAL KW_MATCH match_path where_clause {
$$ = new MatchClause($3, $4, true);
if ($4 && graph::ExpressionUtils::findAny($4->filter(),{Expression::Kind::kAggregate})) {
delete($3);
delete($4);
throw nebula::GraphParser::syntax_error(@4, "Invalid use of aggregating function in this context.");
} else {
$$ = new MatchClause($3, $4, true);
}
}
;

Expand Down
11 changes: 11 additions & 0 deletions src/parser/test/ParserTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2444,6 +2444,17 @@ TEST(Parser, Match) {
}
}

TEST(Parser, MatchErrorCheck) {
{
std::string query = "MATCH (v:player) WHERE count(v)>1 RETURN v";
auto result = parse(query);
ASSERT_FALSE(result.ok());
auto error = "SyntaxError: Invalid use of aggregating "
"function in this context. near `WHERE count(v)>1'";
ASSERT_EQ(error, result.status().toString());
}
}

TEST(Parser, MatchMultipleTags) {
{
std::string query = "MATCH (a:person:player) --> (b) RETURN *";
Expand Down
2 changes: 1 addition & 1 deletion src/validator/MatchValidator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,7 @@ Status MatchValidator::validateStepRange(const MatchStepRange *range) const {
}
if (min < 0) {
return Status::SemanticError(
"Cannot set negtive steps minumum hop for variable length relationships");
"Cannot set negative steps minumum hop for variable length relationships");
}
return Status::OK();
}
Expand Down
3 changes: 3 additions & 0 deletions src/visitor/FoldConstantExprVisitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ void FoldConstantExprVisitor::visit(UnaryExpression *expr) {
if (canBeFolded_) {
expr->setOperand(fold(expr->operand()));
}
} else {
canBeFolded_ = expr->kind() == Expression::Kind::kUnaryNegate ||
expr->kind() == Expression::Kind::kUnaryPlus;
}
}

Expand Down
2 changes: 1 addition & 1 deletion tests/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ gherkin_fmt = ~/.local/bin/reformat-gherkin

RM_DIR ?= true
TEST_DIR ?= $(CURR_DIR)
J ?= 8
J ?= 10

install-deps:
pip3 install --user -U setuptools wheel -i $(PYPI_MIRROR)
Expand Down
32 changes: 22 additions & 10 deletions tests/common/comparator.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import math
import re

from enum import Enum
from typing import Union, Dict, List
from nebula2.common.ttypes import (
DataSet,
Expand All @@ -20,17 +21,19 @@
KV = Dict[Union[str, bytes], Value]
Pattern = type(re.compile(r'/'))

CmpType = Enum('CmpType', ('EQUAL', 'CONTAINS', 'NOT_CONTAINS'))


class DataSetComparator:
def __init__(self,
strict=True,
order=False,
included=False,
decode_type: str = 'utf-8',
contains=CmpType.EQUAL,
decode_type='utf-8',
vid_fn=None):
self._strict = strict
self._order = order
self._included = included
self._contains = contains
self._decode_type = decode_type
self._vid_fn = vid_fn

Expand All @@ -43,12 +46,18 @@ def b(self, v: str) -> bytes:
def s(self, b: bytes) -> str:
return b.decode(self._decode_type)

def _whether_return(self, cmp: bool) -> bool:
return ((self._contains == CmpType.EQUAL and not cmp)
or (self._contains == CmpType.NOT_CONTAINS and cmp))

def compare(self, resp: DataSet, expect: DataSet):
if self._contains == CmpType.NOT_CONTAINS and len(resp.rows) == 0:
return True, None
if all(x is None for x in [expect, resp]):
return True, None
if None in [expect, resp]:
return False, -1
if len(resp.rows) < len(expect.rows):
if len(resp.rows) < len(expect.rows) and self._contains == CmpType.EQUAL:
return False, -1
if len(resp.column_names) != len(expect.column_names):
return False, -1
Expand All @@ -57,13 +66,14 @@ def compare(self, resp: DataSet, expect: DataSet):
return False, -2
if self._order:
for i in range(0, len(expect.rows)):
if not self.compare_row(resp.rows[i], expect.rows[i]):
cmp = self.compare_row(resp.rows[i], expect.rows[i])
if self._whether_return(cmp):
return False, i
if self._included:
if self._contains == CmpType.CONTAINS:
return True, None
return len(resp.rows) == len(expect.rows), -1
return self._compare_list(resp.rows, expect.rows, self.compare_row,
self._included)
self._contains)

def compare_value(self, lhs: Value, rhs: Union[Value, Pattern]) -> bool:
"""
Expand Down Expand Up @@ -327,7 +337,7 @@ def compare_row(self, lhs: Row, rhs: Row):
return all(
self.compare_value(l, r) for (l, r) in zip(lhs.values, rhs.values))

def _compare_list(self, lhs, rhs, cmp_fn, included=False):
def _compare_list(self, lhs, rhs, cmp_fn, contains=False):
visited = []
for j, rr in enumerate(rhs):
found = False
Expand All @@ -336,9 +346,11 @@ def _compare_list(self, lhs, rhs, cmp_fn, included=False):
visited.append(i)
found = True
break
if not found:
if self._whether_return(found):
return False, j
size = len(lhs)
if included:
if contains == CmpType.CONTAINS:
return len(visited) <= size, -1
if contains == CmpType.NOT_CONTAINS:
return True, -1
return len(visited) == size, -1
3 changes: 3 additions & 0 deletions tests/common/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ def use_stmt(self) -> str:
def drop_stmt(self) -> str:
return f"DROP SPACE IF EXISTS `{self.name}`;"

def is_int_vid(self) -> bool:
return self.vid_type == 'int'


class Column:
def __init__(self, index: int):
Expand Down
Loading