Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Fixes #908: Parameters do not survive WITH if it has aggregation

  • Loading branch information...
commit ac395ed9ed8a14d757c90216929023d360a251d0 1 parent 617c794
@systay authored
View
3  cypher/CHANGES.txt
@@ -10,8 +10,9 @@ o Fixed #866: Changed the LRU cache to make it safe to use concurrently, and mad
o Added the reduce() functionality
o Made addition automatically convert numbers to strings when adding the two together
o Added the string functions: str(), replace(), substring(), left(), right(), ltrim(), rtrim(), trim(), lower(), upper()
+o Added the possibility to use ORDER BY, SKIP and LIMIT together with WITH
o Fixes #904: CREATE UNIQUE doesn't work with parameter maps
-
+o Fixes #908: Parameters do not survive WITH if it has aggregation
1.8.RC1 (2012-09-05)
--------------------
View
2  cypher/src/main/scala/org/neo4j/cypher/internal/pipes/ColumnFilterPipe.scala
@@ -38,7 +38,7 @@ class ColumnFilterPipe(source: Pipe, val returnItems: Seq[ReturnItem], lastPipe:
val newMap = MutableMaps.create(ctx.size)
returnItems.foreach {
- case ReturnItem(Identifier(oldName), newName, _) => newMap.put(newName, ctx(oldName))
+ case ReturnItem(Identifier(oldName), newName, _) => newMap.put(newName, ctx(oldName))
case ReturnItem(CachedExpression(oldName, _), newName, _) => newMap.put(newName, ctx(oldName))
case ReturnItem(_, name, _) => newMap.put(name, ctx(name))
}
View
65 cypher/src/main/scala/org/neo4j/cypher/internal/pipes/EagerAggregationPipe.scala
@@ -21,7 +21,7 @@ package org.neo4j.cypher.internal.pipes
import aggregation.AggregationFunction
import org.neo4j.cypher.internal.symbols._
-import org.neo4j.cypher.internal.commands.expressions.{Expression, AggregationExpression}
+import org.neo4j.cypher.internal.commands.expressions.{ParameterValue, Expression, AggregationExpression}
import collection.mutable.{Map => MutableMap}
// Eager aggregation means that this pipe will eagerly load the whole resulting sub graphs before starting
@@ -31,9 +31,9 @@ class EagerAggregationPipe(source: Pipe, val keyExpressions: Map[String, Express
extends PipeWithSource(source) {
def oldKeyExpressions = keyExpressions.values.toSeq
- val symbols: SymbolTable = createSymbols2()
+ val symbols: SymbolTable = createSymbols()
- private def createSymbols2() = {
+ private def createSymbols() = {
val typeExtractor: ((String, Expression)) => (String, CypherType) = {
case (id, exp) => id -> exp.getType(source.symbols)
}
@@ -49,42 +49,49 @@ class EagerAggregationPipe(source: Pipe, val keyExpressions: Map[String, Express
val result = MutableMap[NiceHasher, (ExecutionContext, Seq[AggregationFunction])]()
val keyNames: Seq[String] = keyExpressions.map(_._1).toSeq
val aggregationNames: Seq[String] = aggregations.map(_._1).toSeq
+ val params = state.params.map {
+ case (k, v) => "-=PARAMETER=-" + k + "-=PARAMETER=-" -> ParameterValue(v)
+ }
- source.createResults(state).foreach(ctx => {
- val groupValues: NiceHasher = new NiceHasher(keyNames.map(ctx(_)))
- val (_, functions) = result.getOrElseUpdate(groupValues, (ctx, aggregations.map(_._2.createAggregationFunction).toSeq))
- functions.foreach(func => func(ctx))
- })
+ def createResults(key: NiceHasher, aggregator: scala.Seq[AggregationFunction], ctx: ExecutionContext): ExecutionContext = {
+ val newMap = MutableMaps.create
- if (result.isEmpty && keyNames.isEmpty) {
- createEmptyResult(aggregationNames, state)
- } else result.map {
- case (key, (ctx, aggregator)) => createResults(keyNames, key, aggregationNames, aggregator, ctx)
- }
- }
+ //add key values
+ (keyNames zip key.original).foreach(newMap += _)
+ //add aggregated values
+ (aggregationNames zip aggregator.map(_.result)).foreach(newMap += _)
- def createResults(keyNames: scala.Seq[String], key: NiceHasher, aggregationNames: scala.Seq[String], aggregator: scala.Seq[AggregationFunction], ctx: ExecutionContext): ExecutionContext = {
- val newMap = MutableMaps.create
+ ctx.newFrom(newMap)
+ }
- //add key values
- (keyNames zip key.original).foreach(newMap += _)
+ def createEmptyResult(): Traversable[ExecutionContext] = {
+ val newMap = MutableMaps.create(Parameters.createParamContextMap(state))
+ val aggregationNamesAndFunctions = aggregationNames zip aggregations.map(_._2.createAggregationFunction.result)
+ aggregationNamesAndFunctions.toMap
+ .foreach {
+ case (name, zeroValue) => newMap += name -> zeroValue
+ }
+ Traversable(ExecutionContext(newMap ++ params))
+ }
- //add aggregated values
- (aggregationNames zip aggregator.map(_.result)).foreach(newMap += _)
- ctx.newFrom(newMap)
- }
+ source.createResults(state).foreach(ctx => {
+ val groupValues: NiceHasher = new NiceHasher(keyNames.map(ctx(_)))
+ val (_, functions) = result.getOrElseUpdate(groupValues, (ctx, aggregations.map(_._2.createAggregationFunction).toSeq))
+ functions.foreach(func => func(ctx))
+ })
- private def createEmptyResult(aggregationNames: Seq[String], state : QueryState): Traversable[ExecutionContext] = {
- val newMap = MutableMaps.create(Parameters.createParamContextMap(state))
- val aggregationNamesAndFunctions = aggregationNames zip aggregations.map(_._2.createAggregationFunction.result)
- aggregationNamesAndFunctions.toMap
- .foreach {
- case (name, zeroValue) => newMap += name -> zeroValue
+ val a = if (result.isEmpty && keyNames.isEmpty) {
+ createEmptyResult()
+ } else {
+ result.map {
+ case (key, (ctx, aggregator)) => createResults(key, aggregator, ctx).newWith(params)
+ }
}
- Traversable(ExecutionContext(newMap))
+
+ a
}
override def executionPlan(): String = source.executionPlan() + "\r\n" + "EagerAggregation( keys: [" + oldKeyExpressions.mkString(", ") + "], aggregates: [" + aggregations.mkString(", ") + "])"
View
7 cypher/src/test/scala/org/neo4j/cypher/ExecutionEngineTest.scala
@@ -2258,4 +2258,11 @@ RETURN x0.name?
assert(result.toList === List(Map("n" -> refNode, "collect(x)" -> List())))
}
+ @Test
+ def params_should_survive_with() {
+ val result = parseAndExecute("START n=node(0) WITH collect(n) as coll where length(coll)={id} RETURN coll", "id"->1)
+
+ assert(result.toList === List(Map("coll" -> List(refNode))))
+ }
+
}
View
4 cypher/tech-debt.txt
@@ -1,3 +1,3 @@
-* string.startsWith(" UNNAMED") should be a method
* Strings should all be move into a single file in the parser
-* We need to expose updating statistics for Java objects
+* We need to expose updating statistics for Java objects
+* Parameters should be stored in the QueryState and not in the execution context

0 comments on commit ac395ed

Please sign in to comment.
Something went wrong with that request. Please try again.