Commit 76c0f0cb authored by Pontus Melke's avatar Pontus Melke
Browse files

Merge remote-tracking branch 'upstream/3.1' into 3.2

parents 49f927df 6c0459e7
4.4 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.2.14 3.2.13 3.2.12 3.2.11 3.2.10 3.2.9 3.2.8 3.2.7
No related merge requests found
Showing with 152 additions and 1 deletion
+152 -1
/*
* 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.internal.cypher.acceptance
import org.neo4j.cypher.internal.RewindableExecutionResult
import org.neo4j.cypher.internal.compatibility.ClosingExecutionResult
import org.neo4j.cypher.{ExecutionEngineFunSuite, NewPlannerTestSupport}
import org.neo4j.graphdb.Node
class ShortestPathEdgeCasesAcceptanceTest extends ExecutionEngineFunSuite with NewPlannerTestSupport {
test("GH #5803 query should work with shortest path") {
def createTestGraph() = {
// First create some background graph to get the stats right
(0 to 16).map(_ => createNode()).sliding(2).foreach {
case Seq(n1, n2) => relate(n1, n2)
}
// Now create the specific subgraph used for the test
graph.createIndex("WP", "id")
val query = """create (_31801:`WP` {`id`:1})
|create (_31802:`WP` {`id`:2})
|create (_31803:`WP` {`id`:3})
|create (_31804:`WP` {`id`:4})
|create (_31805:`WP` {`id`:5})
|create (_31806:`WP` {`id`:11})
|create (_31807:`WP` {`id`:12})
|create (_31808:`WP` {`id`:13})
|create (_31809:`WP` {`id`:22})
|create (_31810:`WP` {`id`:23})
|create (_31811:`WP` {`id`:21})
|create (_31812:`WP` {`id`:14})
|create (_31813:`WP` {`id`:29})
|create (_31814:`WP` {`id`:15})
|create (_31815:`WP` {`id`:24})
|create (_31816:`WP` {`id`:25})
|create (_31817:`WP` {`id`:26})
|create (_31818:`WP` {`id`:27})
|create (_31819:`WP` {`id`:28})
|create (_31820:`WP` {`id`:30})
|create (_31801)-[:`SE`]->(_31806)
|create (_31801)-[:`SE`]->(_31802)
|create (_31802)-[:`SE`]->(_31807)
|create (_31802)-[:`SE`]->(_31803)
|create (_31803)-[:`SE`]->(_31808)
|create (_31803)-[:`SE`]->(_31804)
|create (_31804)-[:`SE`]->(_31812)
|create (_31804)-[:`SE`]->(_31805)
|create (_31805)-[:`SE`]->(_31814)
|create (_31805)-[:`SE`]->(_31801)
|create (_31806)-[:`SE`]->(_31809)
|create (_31806)-[:`SE`]->(_31811)
|create (_31806)-[:`SE`]->(_31807)
|create (_31807)-[:`SE`]->(_31815)
|create (_31807)-[:`SE`]->(_31810)
|create (_31807)-[:`SE`]->(_31808)
|create (_31808)-[:`SE`]->(_31817)
|create (_31808)-[:`SE`]->(_31816)
|create (_31808)-[:`SE`]->(_31812)
|create (_31809)-[:`SE`]->(_31811)
|create (_31810)-[:`SE`]->(_31809)
|create (_31811)-[:`SE`]->(_31820)
|create (_31812)-[:`SE`]->(_31819)
|create (_31812)-[:`SE`]->(_31818)
|create (_31812)-[:`SE`]->(_31814)
|create (_31813)-[:`SE`]->(_31819)
|create (_31814)-[:`SE`]->(_31820)
|create (_31814)-[:`SE`]->(_31813)
|create (_31814)-[:`SE`]->(_31806)
|create (_31815)-[:`SE`]->(_31810)
|create (_31816)-[:`SE`]->(_31815)
|create (_31817)-[:`SE`]->(_31816)
|create (_31818)-[:`SE`]->(_31817)
|create (_31819)-[:`SE`]->(_31818)
|create (_31820)-[:`SE`]->(_31813)""".stripMargin
graph.execute(query)
}
createTestGraph()
val query = """WITH [1,3,26,14] as wps
|UNWIND wps AS wpstartid
|UNWIND wps AS wpendid
|WITH wpstartid, wpendid, wps
|WHERE wpstartid<wpendid
|MATCH (wpstart {id:wpstartid})
|MATCH (wpend {id:wpendid})
|MATCH p=shortestPath((wpstart)-[*..10]-(wpend))
|WHERE ALL(id IN wps WHERE id IN EXTRACT(n IN nodes(p) | n.id))
|WITH p, size(nodes(p)) as length order by length limit 1
|RETURN EXTRACT(n IN nodes(p) | n.id) as nodes""".stripMargin
val results = executeWithCostPlannerOnly(query)
results.toList should equal(List(Map("nodes" -> List(1,2,3,4,14,13,26))))
}
test("Predicate should associate with correct shortestPath in complex query") {
// Given query with two shortestPath expressions and a predicate that depends on both paths
val query =
"""
|MATCH (r1:Road) WHERE r1.latitude = 51.357397146246264 AND r1.longitude = -0.20153965352074504
|MATCH (r2:Road) WHERE r2.latitude = 51.36272835382321 AND r2.longitude = -0.16836400394638354
|MATCH path = shortestpath((r1)-[:CONNECTS*]-(r2))
|WITH r1, r2, path
|MATCH returnPath = shortestpath((r2)-[:CONNECTS*]-(r1))
|WHERE none(rel in relationships(returnPath) where rel in relationships(path))
|RETURN returnPath
""".stripMargin
// When executing this query
val result = executeUsingCostPlannerOnly(query)
val shortestPathOperations = result.executionPlanDescription().find("ShortestPath")
val (shortestPathWithPredicate, shortestPathWithoutPredicate) = shortestPathOperations.partition { op =>
op.variables.contains("returnPath")
}
// Then the predicate should only be associated with the correct shortestPath pattern
shortestPathWithPredicate.size should be(1)
shortestPathWithoutPredicate.size should be(1)
val withPredicateOther = shortestPathWithPredicate.head.arguments.map(_.toString).mkString(", ")
val withoutPredicateOther = shortestPathWithoutPredicate.head.arguments.map(_.toString).mkString(", ")
withPredicateOther should include("RelationshipFunction")
withoutPredicateOther should not include "RelationshipFunction"
}
def executeUsingCostPlannerOnly(query: String) =
eengine.execute(s"CYPHER planner=COST $query", Map.empty[String, Any]) match {
case e: ClosingExecutionResult => RewindableExecutionResult(e.inner)
}
}
......@@ -36,8 +36,14 @@ case object planShortestPaths {
(implicit context: LogicalPlanningContext): LogicalPlan = {
val variables = Set(shortestPaths.name, Some(shortestPaths.rel.name)).flatten
def predicateAppliesToShortestPath(p: Predicate) =
// only select predicates related to this pattern (this is code in common with normal MATCH Pattern clauses)
p.hasDependenciesMet(variables ++ inner.availableSymbols) &&
// And filter with predicates that explicitly depend on shortestPath variables
(p.dependencies intersect variables).nonEmpty
val predicates = queryGraph.selections.predicates.collect {
case Predicate(dependencies, expr: Expression) if (dependencies intersect variables).nonEmpty => expr
case p@Predicate(_, expr) if predicateAppliesToShortestPath(p) => expr
}.toIndexedSeq
def doesNotDependOnFullPath(predicate: Expression): Boolean = {
......
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