Skip to content

Commit edeb189

Browse files
committed
fix(cypher): apply distinct before return limits
Signed-off-by: Pcristin <xxxokzxxx@protonmail.com>
1 parent f88d031 commit edeb189

2 files changed

Lines changed: 52 additions & 3 deletions

File tree

src/cypher/cypher.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3267,7 +3267,7 @@ static void build_return_columns(result_builder_t *rb, cbm_return_clause_t *ret)
32673267
static void execute_return_simple(cbm_return_clause_t *ret, binding_t *bindings, int bind_count,
32683268
int max_rows, result_builder_t *rb) {
32693269
int proj_cap = max_rows;
3270-
if (ret->limit > 0 && !ret->order_by && ret->skip <= 0) {
3270+
if (ret->limit > 0 && !ret->distinct && !ret->order_by && ret->skip <= 0) {
32713271
proj_cap = ret->limit;
32723272
}
32733273
for (int bi = 0; bi < bind_count && rb->row_count < proj_cap; bi++) {
@@ -3438,11 +3438,11 @@ static void execute_return_clause(cbm_query_t *q, cbm_return_clause_t *ret, bind
34383438
}
34393439
}
34403440

3441-
rb_apply_order_by(rb, ret);
3442-
rb_apply_skip_limit(rb, ret->skip, ret->limit > 0 ? ret->limit : max_rows);
34433441
if (ret->distinct) {
34443442
rb_apply_distinct(rb);
34453443
}
3444+
rb_apply_order_by(rb, ret);
3445+
rb_apply_skip_limit(rb, ret->skip, ret->limit > 0 ? ret->limit : max_rows);
34463446
}
34473447

34483448
static int execute_single(cbm_store_t *store, cbm_query_t *q, const char *project, int max_rows,

tests/test_cypher.c

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2136,6 +2136,52 @@ TEST(cypher_issue237_distinct_order_limit) {
21362136
PASS();
21372137
}
21382138

2139+
/* #873: duplicate projected rows must be deduped before ORDER BY + LIMIT */
2140+
TEST(cypher_issue873_distinct_order_limit_dedupes_before_limit) {
2141+
cbm_store_t *s = setup_cypher_store();
2142+
cbm_cypher_result_t r = {0};
2143+
int rc = cbm_cypher_execute(
2144+
s, "MATCH (n) RETURN DISTINCT n.label AS label ORDER BY label LIMIT 2", "test", 0, &r);
2145+
ASSERT_EQ(rc, 0);
2146+
ASSERT_NULL(r.error);
2147+
ASSERT_EQ(r.row_count, 2);
2148+
ASSERT_STR_EQ(r.rows[0][0], "Function");
2149+
ASSERT_STR_EQ(r.rows[1][0], "Module");
2150+
cbm_cypher_result_free(&r);
2151+
cbm_store_close(s);
2152+
PASS();
2153+
}
2154+
2155+
/* #873: early LIMIT must not truncate rows before DISTINCT for simple RETURN */
2156+
TEST(cypher_issue873_distinct_limit_dedupes_before_limit) {
2157+
cbm_store_t *s = setup_cypher_store();
2158+
cbm_cypher_result_t r = {0};
2159+
int rc = cbm_cypher_execute(
2160+
s, "MATCH (n) RETURN DISTINCT n.label AS label LIMIT 2", "test", 0, &r);
2161+
ASSERT_EQ(rc, 0);
2162+
ASSERT_NULL(r.error);
2163+
ASSERT_EQ(r.row_count, 2);
2164+
cbm_cypher_result_free(&r);
2165+
cbm_store_close(s);
2166+
PASS();
2167+
}
2168+
2169+
/* #873: SKIP is applied after DISTINCT and ORDER BY, not before dedupe */
2170+
TEST(cypher_issue873_distinct_order_skip_limit_dedupes_before_skip) {
2171+
cbm_store_t *s = setup_cypher_store();
2172+
cbm_cypher_result_t r = {0};
2173+
int rc = cbm_cypher_execute(
2174+
s, "MATCH (n) RETURN DISTINCT n.label AS label ORDER BY label SKIP 1 LIMIT 1", "test",
2175+
0, &r);
2176+
ASSERT_EQ(rc, 0);
2177+
ASSERT_NULL(r.error);
2178+
ASSERT_EQ(r.row_count, 1);
2179+
ASSERT_STR_EQ(r.rows[0][0], "Module");
2180+
cbm_cypher_result_free(&r);
2181+
cbm_store_close(s);
2182+
PASS();
2183+
}
2184+
21392185
/* #252: toInteger() */
21402186
TEST(cypher_issue252_tointeger) {
21412187
cbm_store_t *s = setup_cypher_store();
@@ -2197,6 +2243,9 @@ SUITE(cypher) {
21972243
RUN_TEST(cypher_exec_match_all_functions);
21982244
RUN_TEST(cypher_issue240_labels_function);
21992245
RUN_TEST(cypher_issue237_distinct_order_limit);
2246+
RUN_TEST(cypher_issue873_distinct_order_limit_dedupes_before_limit);
2247+
RUN_TEST(cypher_issue873_distinct_limit_dedupes_before_limit);
2248+
RUN_TEST(cypher_issue873_distinct_order_skip_limit_dedupes_before_skip);
22002249
RUN_TEST(cypher_issue252_tointeger);
22012250
RUN_TEST(cypher_issue305_count_star_alias);
22022251
RUN_TEST(cypher_exec_where_eq);

0 commit comments

Comments
 (0)