Skip to content
Open
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
6 changes: 3 additions & 3 deletions src/cypher/cypher.c
Original file line number Diff line number Diff line change
Expand Up @@ -4105,7 +4105,7 @@ static void build_return_columns(result_builder_t *rb, cbm_return_clause_t *ret)
static void execute_return_simple(cbm_return_clause_t *ret, binding_t *bindings, int bind_count,
int max_rows, result_builder_t *rb) {
int proj_cap = max_rows;
if (ret->limit > 0 && !ret->order_by && ret->skip <= 0) {
if (ret->limit > 0 && !ret->distinct && !ret->order_by && ret->skip <= 0) {
proj_cap = ret->limit;
}
for (int bi = 0; bi < bind_count && rb->row_count < proj_cap; bi++) {
Expand Down Expand Up @@ -4387,11 +4387,11 @@ static void execute_return_clause(cbm_query_t *q, cbm_return_clause_t *ret, bind
}
}

rb_apply_order_by(rb, ret);
rb_apply_skip_limit(rb, ret->skip, ret->limit >= 0 ? ret->limit : max_rows);
if (ret->distinct) {
rb_apply_distinct(rb);
}
rb_apply_order_by(rb, ret);
rb_apply_skip_limit(rb, ret->skip, ret->limit >= 0 ? ret->limit : max_rows);
}

static int execute_single(cbm_store_t *store, cbm_query_t *q, const char *project, int max_rows,
Expand Down
49 changes: 49 additions & 0 deletions tests/test_cypher.c
Original file line number Diff line number Diff line change
Expand Up @@ -2524,6 +2524,52 @@ TEST(cypher_issue237_distinct_order_limit) {
PASS();
}

/* #873: duplicate projected rows must be deduped before ORDER BY + LIMIT */
TEST(cypher_issue873_distinct_order_limit_dedupes_before_limit) {
cbm_store_t *s = setup_cypher_store();
cbm_cypher_result_t r = {0};
int rc = cbm_cypher_execute(
s, "MATCH (n) RETURN DISTINCT n.label AS label ORDER BY label LIMIT 2", "test", 0, &r);
ASSERT_EQ(rc, 0);
ASSERT_NULL(r.error);
ASSERT_EQ(r.row_count, 2);
ASSERT_STR_EQ(r.rows[0][0], "Function");
ASSERT_STR_EQ(r.rows[1][0], "Module");
cbm_cypher_result_free(&r);
cbm_store_close(s);
PASS();
}

/* #873: early LIMIT must not truncate rows before DISTINCT for simple RETURN */
TEST(cypher_issue873_distinct_limit_dedupes_before_limit) {
cbm_store_t *s = setup_cypher_store();
cbm_cypher_result_t r = {0};
int rc = cbm_cypher_execute(
s, "MATCH (n) RETURN DISTINCT n.label AS label LIMIT 2", "test", 0, &r);
ASSERT_EQ(rc, 0);
ASSERT_NULL(r.error);
ASSERT_EQ(r.row_count, 2);
cbm_cypher_result_free(&r);
cbm_store_close(s);
PASS();
}

/* #873: SKIP is applied after DISTINCT and ORDER BY, not before dedupe */
TEST(cypher_issue873_distinct_order_skip_limit_dedupes_before_skip) {
cbm_store_t *s = setup_cypher_store();
cbm_cypher_result_t r = {0};
int rc = cbm_cypher_execute(
s, "MATCH (n) RETURN DISTINCT n.label AS label ORDER BY label SKIP 1 LIMIT 1", "test",
0, &r);
ASSERT_EQ(rc, 0);
ASSERT_NULL(r.error);
ASSERT_EQ(r.row_count, 1);
ASSERT_STR_EQ(r.rows[0][0], "Module");
cbm_cypher_result_free(&r);
cbm_store_close(s);
PASS();
}

/* #252: toInteger() */
TEST(cypher_issue252_tointeger) {
cbm_store_t *s = setup_cypher_store();
Expand Down Expand Up @@ -2624,6 +2670,9 @@ SUITE(cypher) {
RUN_TEST(cypher_exec_match_all_functions);
RUN_TEST(cypher_issue240_labels_function);
RUN_TEST(cypher_issue237_distinct_order_limit);
RUN_TEST(cypher_issue873_distinct_order_limit_dedupes_before_limit);
RUN_TEST(cypher_issue873_distinct_limit_dedupes_before_limit);
RUN_TEST(cypher_issue873_distinct_order_skip_limit_dedupes_before_skip);
RUN_TEST(cypher_issue252_tointeger);
RUN_TEST(cypher_issue305_count_star_alias);
RUN_TEST(cypher_exec_where_eq);
Expand Down
Loading