diff --git a/airframe-sql/src/main/scala/wvlet/airframe/sql/model/Expression.scala b/airframe-sql/src/main/scala/wvlet/airframe/sql/model/Expression.scala index eb4d229e6..a4a0b1f59 100644 --- a/airframe-sql/src/main/scala/wvlet/airframe/sql/model/Expression.scala +++ b/airframe-sql/src/main/scala/wvlet/airframe/sql/model/Expression.scala @@ -1336,4 +1336,10 @@ object Expression { override def toString = s"Extract(interval:${interval}, ${expr})" } + case class Position(substring: Expression, string: Expression, nodeLocation: Option[NodeLocation]) + extends Expression { + override def children: Seq[Expression] = Seq(substring, string) + override def sqlExpr: String = s"POSITION(${substring.sqlExpr} IN ${string.sqlExpr})" + override def toString = sqlExpr + } } diff --git a/airframe-sql/src/main/scala/wvlet/airframe/sql/parser/SQLInterpreter.scala b/airframe-sql/src/main/scala/wvlet/airframe/sql/parser/SQLInterpreter.scala index 925443edf..da5ac538d 100644 --- a/airframe-sql/src/main/scala/wvlet/airframe/sql/parser/SQLInterpreter.scala +++ b/airframe-sql/src/main/scala/wvlet/airframe/sql/parser/SQLInterpreter.scala @@ -992,4 +992,8 @@ class SQLInterpreter(withNodeLocation: Boolean = true) extends SqlBaseBaseVisito val ifExists = Option(ctx.EXISTS()).map(x => true).getOrElse(false) DropView(viewName, ifExists, getLocation(ctx)) } + + override def visitPosition(ctx: PositionContext): Expression = { + Position(expression(ctx.valueExpression(0)), expression(ctx.valueExpression(1)), getLocation(ctx)) + } } diff --git a/airframe-sql/src/test/scala/wvlet/airframe/sql/parser/SQLGeneratorTest.scala b/airframe-sql/src/test/scala/wvlet/airframe/sql/parser/SQLGeneratorTest.scala index 137762574..2da0e7c26 100644 --- a/airframe-sql/src/test/scala/wvlet/airframe/sql/parser/SQLGeneratorTest.scala +++ b/airframe-sql/src/test/scala/wvlet/airframe/sql/parser/SQLGeneratorTest.scala @@ -194,4 +194,12 @@ class SQLGeneratorTest extends AirSpec { val sql = SQLGenerator.print(resolvedPlan) sql shouldBe "SELECT TIMESTAMP '1992-02-01 00:00 UTC' AT TIME ZONE 'Asia/Tokyo'" } + + test("print POSITION") { + val resolvedPlan = + SQLAnalyzer.analyze("SELECT xid FROM A WHERE POSITION('str' IN xid) > 0", "default", demoCatalog) + + val sql = SQLGenerator.print(resolvedPlan) + sql shouldBe "SELECT xid FROM A WHERE POSITION('str' IN xid) > 0" + } }