Skip to content

Commit a9ad186

Browse files
author
CNE Pierre FICHEPOIL
committed
fixes #3329
1 parent 3bbc685 commit a9ad186

File tree

2 files changed

+88
-24
lines changed

2 files changed

+88
-24
lines changed

engine/src/main/java/com/arcadedb/query/opencypher/executor/CypherExecutionPlan.java

Lines changed: 27 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -599,32 +599,35 @@ private AbstractExecutionStep buildExecutionStepsWithOrder(final CommandContext
599599
if (typeCountStep != null)
600600
return typeCountStep;
601601

602-
// Special case: RETURN without MATCH (standalone expressions)
603-
// E.g., RETURN abs(-42), RETURN 1+1
604-
if (statement.getMatchClauses().isEmpty() && statement.getReturnClause() != null &&
605-
clausesInOrder.stream().noneMatch(c -> c.getType() == ClauseEntry.ClauseType.UNWIND)) {
606-
// Create a dummy row to evaluate expressions against
607-
final ResultInternal dummyRow = new ResultInternal();
608-
final List<Result> singleRow = List.of(dummyRow);
609-
610-
// Return the single row via an initial step
611-
currentStep = new AbstractExecutionStep(context) {
612-
private boolean consumed = false;
613-
614-
@Override
615-
public ResultSet syncPull(final CommandContext ctx, final int nRecords) {
616-
if (consumed) {
617-
return new IteratorResultSet(List.<ResultInternal>of().iterator());
602+
// Special case: Standalone WITH, UNWIND, or RETURN
603+
if (!clausesInOrder.isEmpty()) {
604+
final ClauseEntry.ClauseType firstClauseType = clausesInOrder.get(0).getType();
605+
if (firstClauseType == ClauseEntry.ClauseType.WITH ||
606+
firstClauseType == ClauseEntry.ClauseType.UNWIND ||
607+
(firstClauseType == ClauseEntry.ClauseType.RETURN && statement.getMatchClauses().isEmpty())) {
608+
// Create a dummy row to evaluate expressions against
609+
final ResultInternal dummyRow = new ResultInternal();
610+
final List<Result> singleRow = List.of(dummyRow);
611+
612+
// Return the single row via an initial step
613+
currentStep = new AbstractExecutionStep(context) {
614+
private boolean consumed = false;
615+
616+
@Override
617+
public ResultSet syncPull(final CommandContext ctx, final int nRecords) {
618+
if (consumed) {
619+
return new IteratorResultSet(List.<ResultInternal>of().iterator());
620+
}
621+
consumed = true;
622+
return new IteratorResultSet(singleRow.iterator());
618623
}
619-
consumed = true;
620-
return new IteratorResultSet(singleRow.iterator());
621-
}
622624

623-
@Override
624-
public String prettyPrint(final int depth, final int indent) {
625-
return " ".repeat(Math.max(0, depth * indent)) + "+ DUMMY ROW (for standalone expressions)";
626-
}
627-
};
625+
@Override
626+
public String prettyPrint(final int depth, final int indent) {
627+
return " ".repeat(Math.max(0, depth * indent)) + "+ DUMMY ROW (for standalone expressions)";
628+
}
629+
};
630+
}
628631
}
629632

630633
// Process clauses in order
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* Copyright © 2021-present Arcade Data Ltd (info@arcadedata.com)
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
* SPDX-FileCopyrightText: 2021-present Arcade Data Ltd (info@arcadedata.com)
17+
* SPDX-License-Identifier: Apache-2.0
18+
*/
19+
package com.arcadedb.query.opencypher;
20+
21+
import com.arcadedb.database.Database;
22+
import com.arcadedb.database.DatabaseFactory;
23+
import com.arcadedb.query.sql.executor.Result;
24+
import com.arcadedb.query.sql.executor.ResultSet;
25+
import org.junit.jupiter.api.AfterEach;
26+
import org.junit.jupiter.api.BeforeEach;
27+
import org.junit.jupiter.api.Test;
28+
29+
import static org.junit.jupiter.api.Assertions.assertEquals;
30+
import static org.junit.jupiter.api.Assertions.assertFalse;
31+
import static org.junit.jupiter.api.Assertions.assertTrue;
32+
33+
public class OpenCypherIssuesTest {
34+
private Database database;
35+
36+
@BeforeEach
37+
void setUp() {
38+
database = new DatabaseFactory("./target/databases/testopencypher-issues").create();
39+
}
40+
41+
@AfterEach
42+
void tearDown() {
43+
if (database != null) {
44+
database.drop();
45+
database = null;
46+
}
47+
}
48+
49+
@Test
50+
void unwindWithNestedList() {
51+
final String query = "WITH [[1, 2], [3, 4], []] AS nested\n" +
52+
"UNWIND nested AS x\n" +
53+
"UNWIND x AS y\n" +
54+
"RETURN count(y) AS total";
55+
final ResultSet result = database.query("opencypher", query);
56+
assertTrue(result.hasNext());
57+
final Result row = result.next();
58+
assertEquals(4L, (long) row.getProperty("total"));
59+
assertFalse(result.hasNext());
60+
}
61+
}

0 commit comments

Comments
 (0)