/
H2Driver.scala
65 lines (56 loc) · 2.57 KB
/
H2Driver.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
package scala.slick.driver
import scala.slick.lifted._
import scala.slick.ast._
import scala.slick.ast.Util._
import scala.slick.ast.ExtraUtil._
import scala.slick.SlickException
/**
* SLICK driver for H2.
*
* <p>This driver implements the ExtendedProfile with the following
* limitations:</p>
* <ul>
* <li>When returning columns from an INSERT operation, only a single column
* may be specified which must be the table's AutoInc column.</li>
* </ul>
*
* @author szeiger
*/
trait H2Driver extends ExtendedDriver { driver =>
override val supportsArbitraryInsertReturnColumns = false
override def createQueryBuilder(input: QueryBuilderInput): QueryBuilder = new QueryBuilder(input)
override def mapTypeName(tmd: TypeMapperDelegate[_]): String = tmd.sqlType match {
case java.sql.Types.VARCHAR => "VARCHAR"
case _ => super.mapTypeName(tmd)
}
class QueryBuilder(input: QueryBuilderInput) extends super.QueryBuilder(input) {
override protected val concatOperator = Some("||")
override protected def toComprehension(n: Node, liftExpression: Boolean = false) =
super.toComprehension(n, liftExpression) match {
case c @ Comprehension(from, _, None, orderBy, Some(sel), _, _) if !orderBy.isEmpty && hasRowNumber(sel) =>
// H2 supports only Oracle-style ROWNUM (applied before ORDER BY and GROUP BY),
// so we pull the SELECT clause with the ROWNUM up into a new query
val paths = findPaths(from.map(_._1).toSet, sel).map(p => (p, new AnonSymbol)).toMap
val inner = c.copy(select = Some(Pure(StructNode(paths.toIndexedSeq.map { case (n,s) => (s,n) }))))
val gen = new AnonSymbol
val newSel = sel.replace {
case s: Select => paths.get(s).fold(s) { sym => Select(Ref(gen), sym) }
}
Comprehension(Seq((gen, inner)), select = Some(newSel))
case c => c
}
override def expr(n: Node, skipParens: Boolean = false) = n match {
case Library.NextValue(SequenceNode(name)) => b += "nextval(schema(), '" += name += "')"
case Library.CurrentValue(SequenceNode(name)) => b += "currval(schema(), '" += name += "')"
case RowNumber(_) => b += "rownum()"
case _ => super.expr(n, skipParens)
}
override protected def buildFetchOffsetClause(fetch: Option[Long], offset: Option[Long]) = (fetch, offset) match {
case (Some(t), Some(d)) => b += " LIMIT " += t += " OFFSET " += d
case (Some(t), None) => b += " LIMIT " += t
case (None, Some(d)) => b += " LIMIT -1 OFFSET " += d
case _ =>
}
}
}
object H2Driver extends H2Driver