Commit d0371171 authored by Louise Söderström's avatar Louise Söderström
Browse files

Fix shortest path in with clause bug

Semantic check claimed shortest path returned a list
Unwind didn't work for the Scala iterator returned by allShortestPaths
parent a76f153b
4.4 3.1 3.2 3.3 3.3-report-costs 3.4 3.5 3.5-compiled-expression 3.5-no-more-longarray-hashing 4.0 4.1 4.2 4.2-pipelined 4.3 5.0 5.1 5.2 akollegger-patch-1 issue-management-update revert-12892-feature/upd testwin/3.3-ref-from-slot-name testwin/3.4-failing-windows 5.2.0 5.1.0 5.0.0 4.4.14 4.4.13 4.4.12 4.4.11 4.4.10 4.4.9 4.4.8 4.4.7 4.4.6 4.4.5 4.4.4 4.4.3 4.4.2 4.4.1 4.4.0 4.4.0-alpha01 4.3.21 4.3.20 4.3.19 4.3.18 4.3.17 4.3.16 4.3.15 4.3.14 4.3.13 4.3.12 4.3.11 4.3.10 4.3.9 4.3.8 4.3.7 4.3.6 4.3.5 4.3.4 4.3.3 4.3.2 4.3.1 4.3.0 4.2.19 4.2.18 4.2.17 4.2.16 4.2.15 4.2.14 4.2.13 4.2.12 4.2.11 4.2.10 4.2.9 4.2.8 4.2.7 4.2.6 4.2.5 4.2.4 4.2.3 4.2.2 4.2.1 4.2.0 4.1.12 4.1.11 4.1.10 4.1.9 4.1.8 4.1.7 4.1.6 4.1.5 4.1.4 4.1.3 4.1.2 4.1.1 4.1.0 4.1.0-alpha01 4.0.12 4.0.11 4.0.10 4.0.9 4.0.8 4.0.7 4.0.6 4.0.5 4.0.4 4.0.3 4.0.2 4.0.1 4.0.0 4.0.0-rc01 4.0.0-beta03mr03 4.0.0-beta02 4.0.0-beta01 4.0.0-alpha10 4.0.0-alpha09mr02 4.0.0-alpha08 4.0.0-alpha07mr01 4.0.0-alpha06 4.0.0-alpha05 4.0.0-alpha04 4.0.0-alpha03 4.0.0-alpha02 4.0.0-alpha01 3.5.35 3.5.34 3.5.33 3.5.32 3.5.31 3.5.30 3.5.29 3.5.28 3.5.27 3.5.26 3.5.25 3.5.24 3.5.23 3.5.22 3.5.21 3.5.20 3.5.19 3.5.18 3.5.17 3.5.16 3.5.15 3.5.14 3.5.13 3.5.12 3.5.11 3.5.9 3.5.8 3.5.7 3.5.6 3.5.5 3.5.4 3.5.3 3.5.2 3.5.1 3.5.0 3.5.0-rc01 3.5.0-beta03 3.5.0-beta02 3.5.0-beta01 3.5.0-alpha09 3.5.0-alpha08 3.5.0-alpha07 3.5.0-alpha06 3.5.0-alpha05 3.5.0-alpha04 3.5.0-alpha02 3.5.0-alpha01 3.4.18 3.4.17 3.4.16 3.4.15 3.4.14 3.4.13 3.4.12 3.4.11 3.4.10 3.4.9 3.4.8 3.4.7 3.4.6 3.4.5 3.4.4 3.4.2 3.4.1 3.4.0 3.4.0-rc02 3.4.0-rc01 3.4.0-beta02 3.4.0-beta01 3.4.0-alpha10 3.4.0-alpha09 3.4.0-alpha08 3.4.0-alpha07 3.4.0-alpha06 3.4.0-alpha05 3.4.0-alpha04 3.4.0-alpha03 3.4.0-alpha02 3.4.0-alpha01 3.3.9 3.3.8 3.3.7 3.3.6 3.3.5 3.3.4 3.3.3 3.3.2 3.3.1 3.3.0 3.2.14 3.2.13 3.2.12 3.2.11 3.2.10 3.2.9 3.2.8 3.2.7 3.1.9 3.1.8
No related merge requests found
Showing with 140 additions and 2 deletions
+140 -2
......@@ -31,7 +31,7 @@ class ShortestPathAcceptanceTest extends ExecutionEngineFunSuite with NewPlanner
var nodeC: Node = _
var nodeD: Node = _
override def databaseConfig = Map(GraphDatabaseSettings.forbid_shortestpath_common_nodes -> "false")
override def databaseConfig() = Map(GraphDatabaseSettings.forbid_shortestpath_common_nodes -> "false")
override protected def initTest(): Unit = {
super.initTest()
......@@ -41,6 +41,72 @@ class ShortestPathAcceptanceTest extends ExecutionEngineFunSuite with NewPlanner
nodeD = createLabeledNode("D")
}
test("shortest path in a with clause") {
relate(nodeA, nodeB)
val query =
"""
| MATCH (a:A), (b:B)
| WITH shortestPath((a)-[:REL]->(b)) AS x
| RETURN nodes(x)
""".stripMargin
val result = executeWithAllPlanners(query).columnAs[List[Node]]("nodes(x)").toList
result should equal(List(List(nodeA, nodeB)))
}
test("shortest path in a with clause and no paths found") {
relate(nodeA, nodeB)
val query =
"""
| MATCH (a:A), (b:B)
| WITH shortestPath((a)-[:XXX]->(b)) AS x
| RETURN nodes(x)
""".stripMargin
val result = executeWithAllPlanners(query).columnAs[List[Node]]("nodes(x)").toList
result should equal(List(null))
}
test("all shortest paths in a with clause") {
relate(nodeA, nodeB)
val query =
"""
| MATCH (a:A), (b:B)
| WITH allShortestPaths((a)-[:REL]->(b)) AS p
| UNWIND p AS x
| RETURN nodes(x)
""".stripMargin
val result = executeWithAllPlanners(query).columnAs[List[Node]]("nodes(x)").toList
result should equal(List(List(nodeA, nodeB)))
}
test("all shortest paths in a with clause and no paths found") {
relate(nodeA, nodeB)
val query =
"""
| MATCH (a:A), (b:B)
| WITH allShortestPaths((a)-[:XXX]->(b)) AS p
| UNWIND p AS x
| RETURN nodes(x)
""".stripMargin
val result = executeWithAllPlanners(query).columnAs[List[Node]]("nodes(x)").toList
result should equal(List.empty)
}
// THESE NEED TO BE REVIEWED FOR SEMANTIC CORRECTNESS
test("unnamed shortest path with fallback-required predicate should work") {
val r1 = relate(nodeA, nodeB, "bar" -> 1)
......
......@@ -89,6 +89,7 @@ trait ListSupport {
case x: Map[_, _] => Iterable(x)
case x: JavaMap[_, _] => Iterable(x.asScala)
case x: Traversable[_] => x.toIterable
case x: Iterator[_] => x.toIterable
case x: JavaIterable[_] => x.asScala.map {
case y: JavaMap[_, _] => y.asScala
case y => y
......
......@@ -24,7 +24,7 @@ import org.neo4j.cypher.internal.frontend.v3_1.symbols._
case class ShortestPathExpression(pattern: ShortestPaths) extends Expression with SimpleTyping {
def position = pattern.position
protected def possibleTypes = CTList(CTPath)
protected def possibleTypes = if (pattern.single) CTPath else CTList(CTPath)
override def semanticCheck(ctx: SemanticContext) =
pattern.declareVariables(Pattern.SemanticContext.Expression) chain
......
/*
* Copyright (c) 2002-2017 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.neo4j.cypher.internal.frontend.v3_1.ast
import org.neo4j.cypher.internal.frontend.v3_1.symbols._
import org.neo4j.cypher.internal.frontend.v3_1.{SemanticDirection, SemanticState}
import org.neo4j.cypher.internal.frontend.v3_1.test_helpers.CypherFunSuite
class ShortestPathExpressionTest extends CypherFunSuite with AstConstructionTestSupport {
test("should get correct types for shortestPath") {
// Given
val (exp, state) = makeShortestPathExpression(true)
// When
val result = exp.semanticCheck(Expression.SemanticContext.Simple)(state)
// Then
result.errors shouldBe empty
exp.types(result.state) should equal(TypeSpec.exact(CTPath))
}
test("should get correct types for allShortestPath") {
// Given
val (exp, state) = makeShortestPathExpression(false)
// When
val result = exp.semanticCheck(Expression.SemanticContext.Simple)(state)
// Then
result.errors shouldBe empty
exp.types(result.state) should equal(TypeSpec.exact(CTList(CTPath)))
}
private def makeShortestPathExpression(single: Boolean): (ShortestPathExpression, SemanticState) = {
val state = Seq("n", "k").foldLeft(SemanticState.clean) { (acc, n) =>
acc.specifyType(varFor(n), TypeSpec.exact(CTNode)).right.get
}
val pattern = chain(node(Some(varFor("n"))), relationship(None), node(Some(varFor("k"))))
(ShortestPathExpression(ShortestPaths(pattern, single) _), state)
}
private def chain(left: PatternElement, rel: RelationshipPattern, right: NodePattern): RelationshipChain = {
RelationshipChain(left, rel, right)_
}
private def relationship(id: Option[Variable]): RelationshipPattern = {
RelationshipPattern(id, optional = false, Seq.empty, None, None, SemanticDirection.OUTGOING)_
}
private def node(id: Option[Variable]): NodePattern = {
NodePattern(id, Seq.empty, None)_
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment