Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ package org.apache.spark.sql.catalyst.expressions
import org.apache.spark.sql.catalyst.analysis.UnresolvedException
import org.apache.spark.sql.catalyst.plans.logical.LogicalPlan
import org.apache.spark.sql.catalyst.types.BooleanType

import scala.collection.immutable.HashSet

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Scala import should go first. See here for more details.


object InterpretedPredicate {
def apply(expression: Expression, inputSchema: Seq[Attribute]): (Row => Boolean) =
Expand Down Expand Up @@ -95,6 +95,21 @@ case class In(value: Expression, list: Seq[Expression]) extends Predicate {
}
}

/**
* Evaluates to `true` if `list` contains `value`.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a comment that this is an optimized version of In for when all values of the inList are static.

*/
case class InSet(value: Expression, hset: HashSet[Any], child: Seq[Expression])
extends Predicate {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should actually only be indented 2 spaces (and I'd include a blank line after). Only wrapped arguments are indented 4.

def children = child

def nullable = true // TODO: Figure out correct nullability semantics of IN.
override def toString = s"$value IN ${hset.mkString("(", ",", ")")}"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd actually say InSet here as the toString is mostly for debugging / understanding how queries will execute.


override def eval(input: Row): Any = {
hset.contains(value.eval(input))
}
}

case class And(left: Expression, right: Expression) extends BinaryPredicate {
def symbol = "&&"

Expand Down
12 changes: 11 additions & 1 deletion sql/hive/src/main/scala/org/apache/spark/sql/hive/HiveQl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import org.apache.spark.sql.catalyst.plans.logical
import org.apache.spark.sql.catalyst.plans.logical._
import org.apache.spark.sql.catalyst.types._

import scala.collection.immutable.HashSet
/* Implicit conversions */
import scala.collection.JavaConversions._

Expand Down Expand Up @@ -977,7 +978,16 @@ private[hive] object HiveQl {
case Token("TOK_FUNCTION", Token("TOK_ISNULL", Nil) :: child :: Nil) =>
IsNull(nodeToExpr(child))
case Token("TOK_FUNCTION", Token(IN(), Nil) :: value :: list) =>
In(nodeToExpr(value), list.map(nodeToExpr))
val valExpr = nodeToExpr(value)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of hardwiring this into the parser, lets create a rule in Optimizer.scala that recognizes this pattern. That will allow this optimization to be more general. For example it could then easily apply to queries like ... WHERE x IN (1 + 1, 1 + 2, ...) since it'll happen along with ConstantFolding.

val listMap = list.map(nodeToExpr)
if (listMap.exists(e => ((!e.isInstanceOf[Literal]) &&
(!e.isInstanceOf[UnaryMinus]))) == false){
val hSet = listMap.map(e => e.eval(null))
InSet(valExpr, HashSet() ++ hSet, valExpr +: listMap)
}
else{
In(valExpr, listMap)
}
case Token("TOK_FUNCTION",
Token(BETWEEN(), Nil) ::
Token("KW_FALSE", Nil) ::
Expand Down