Permalink
Browse files

Add Query#subquery as a precaution for implementing workarounds.

Bugs in the more aggressive query fusion in 3.1 or possible performance
issues in edge cases (as mentioned in #1282) should often be avoidable
by forcing a subquery to be created at a certain point. This change
adds an operator for this purpose to the API. We may remove it in a
later version when we feel confident that all problems of this kind have
been stamped out.

Test in NewQuerySemanticsTest.testNewFusion.
  • Loading branch information...
szeiger committed Sep 23, 2015
1 parent 8f8ae8b commit 84cc95aeb539b059e903da9fcd9ce0065186a238
@@ -503,6 +503,7 @@ class NewQuerySemanticsTest extends AsyncTest[RelationalTestDB] {
val q17 = as.sortBy(_.id).zipWithIndex.filter(_._2 < 2L).map { case (a, i) => (a.id, i) }
val q18 = as.joinLeft(as).on { case (a1, a2) => a1.id === a2.id }.filter { case (a1, a2) => a1.id === 3 }.map { case (a1, a2) => a2 }
val q19 = as.joinLeft(as).on { case (a1, a2) => a1.id === a2.id }.joinLeft(as).on { case ((_, a2), a3) => a2.map(_.b) === a3.b }.map(_._2)
val q19b = as.joinLeft(as).on { case (a1, a2) => a1.id === a2.id }.joinLeft(as).on { case ((_, a2), a3) => a2.map(_.b) === a3.b }.subquery.map(_._2)
if(tdb.driver == H2Driver) {
assertNesting(q1, 1)
@@ -532,6 +533,7 @@ class NewQuerySemanticsTest extends AsyncTest[RelationalTestDB] {
assertNesting(q17, 2)
assertNesting(q18, 1)
assertNesting(q19, 1)
assertNesting(q19b, 2)
}
for {
@@ -565,6 +567,7 @@ class NewQuerySemanticsTest extends AsyncTest[RelationalTestDB] {
_ <- ifCap(rcap.zip)(mark("q17", q17.result).map(_ shouldBe Seq((1,0), (2,1))))
_ <- mark("q18", q18.result).map(_ shouldBe Seq(Some((3, "c", "b"))))
_ <- mark("q19", q19.result).map(_.toSet shouldBe Set(Some((1,"a","a")), Some((2,"a","b")), Some((3,"c","b"))))
_ <- mark("q19b", q19b.result).map(_.toSet shouldBe Set(Some((1,"a","a")), Some((2,"a","b")), Some((3,"c","b"))))
} yield ()
}
}
@@ -223,6 +223,12 @@ sealed abstract class Query[+E, U, C[_]] extends QueryBase[C[U]] { self =>
val shaped = self.shaped
def toNode = CollectionCast(self.toNode, ctc)
}
/** Force a subquery to be created when using this Query as part of a larger Query. This method
* should never be necessary for correctness. If a query works with an explicit `.subquery` call
* but fails without, this should be considered a bug in Slick. The method is exposed in the API
* to enable workarounds to be written in such cases. */
def subquery: Query[E, U, C] = new WrappingQuery[E, U, C](Subquery(toNode, Subquery.Default), shaped)
}
/** The companion object for Query contains factory methods for creating queries. */
@@ -330,6 +330,7 @@ class QueryInterpreter(db: HeapBackend#Database, params: Any) extends Logging {
//case Library.CountAll(ch) => run(ch).asInstanceOf[Coll].size
case l: LiteralNode => l.value
case CollectionCast(ch, _) => run(ch)
case Subquery(ch, _) => run(ch)
}
indent -= 1
if(logger.isDebugEnabled) logDebug("Result: "+res)

0 comments on commit 84cc95a

Please sign in to comment.