Skip to content
Snippets Groups Projects
Commit b1436c74 authored by Reynold Xin's avatar Reynold Xin Committed by Xiao Li
Browse files

[SPARK-21059][SQL] LikeSimplification can NPE on null pattern

## What changes were proposed in this pull request?
This patch fixes a bug that can cause NullPointerException in LikeSimplification, when the pattern for like is null.

## How was this patch tested?
Added a new unit test case in LikeSimplificationSuite.

Author: Reynold Xin <rxin@databricks.com>

Closes #18273 from rxin/SPARK-21059.
parent 32818d9b
No related branches found
No related tags found
No related merge requests found
...@@ -383,22 +383,27 @@ object LikeSimplification extends Rule[LogicalPlan] { ...@@ -383,22 +383,27 @@ object LikeSimplification extends Rule[LogicalPlan] {
def apply(plan: LogicalPlan): LogicalPlan = plan transformAllExpressions { def apply(plan: LogicalPlan): LogicalPlan = plan transformAllExpressions {
case Like(input, Literal(pattern, StringType)) => case Like(input, Literal(pattern, StringType)) =>
pattern.toString match { if (pattern == null) {
case startsWith(prefix) if !prefix.endsWith("\\") => // If pattern is null, return null value directly, since "col like null" == null.
StartsWith(input, Literal(prefix)) Literal(null, BooleanType)
case endsWith(postfix) => } else {
EndsWith(input, Literal(postfix)) pattern.toString match {
// 'a%a' pattern is basically same with 'a%' && '%a'. case startsWith(prefix) if !prefix.endsWith("\\") =>
// However, the additional `Length` condition is required to prevent 'a' match 'a%a'. StartsWith(input, Literal(prefix))
case startsAndEndsWith(prefix, postfix) if !prefix.endsWith("\\") => case endsWith(postfix) =>
And(GreaterThanOrEqual(Length(input), Literal(prefix.size + postfix.size)), EndsWith(input, Literal(postfix))
And(StartsWith(input, Literal(prefix)), EndsWith(input, Literal(postfix)))) // 'a%a' pattern is basically same with 'a%' && '%a'.
case contains(infix) if !infix.endsWith("\\") => // However, the additional `Length` condition is required to prevent 'a' match 'a%a'.
Contains(input, Literal(infix)) case startsAndEndsWith(prefix, postfix) if !prefix.endsWith("\\") =>
case equalTo(str) => And(GreaterThanOrEqual(Length(input), Literal(prefix.length + postfix.length)),
EqualTo(input, Literal(str)) And(StartsWith(input, Literal(prefix)), EndsWith(input, Literal(postfix))))
case _ => case contains(infix) if !infix.endsWith("\\") =>
Like(input, Literal.create(pattern, StringType)) Contains(input, Literal(infix))
case equalTo(str) =>
EqualTo(input, Literal(str))
case _ =>
Like(input, Literal.create(pattern, StringType))
}
} }
} }
} }
......
...@@ -17,13 +17,13 @@ ...@@ -17,13 +17,13 @@
package org.apache.spark.sql.catalyst.optimizer package org.apache.spark.sql.catalyst.optimizer
/* Implicit conversions */
import org.apache.spark.sql.catalyst.dsl.expressions._ import org.apache.spark.sql.catalyst.dsl.expressions._
import org.apache.spark.sql.catalyst.dsl.plans._ import org.apache.spark.sql.catalyst.dsl.plans._
import org.apache.spark.sql.catalyst.expressions._ import org.apache.spark.sql.catalyst.expressions._
import org.apache.spark.sql.catalyst.plans.logical._ import org.apache.spark.sql.catalyst.plans.logical._
import org.apache.spark.sql.catalyst.plans.PlanTest import org.apache.spark.sql.catalyst.plans.PlanTest
import org.apache.spark.sql.catalyst.rules._ import org.apache.spark.sql.catalyst.rules._
import org.apache.spark.sql.types.{BooleanType, StringType}
class LikeSimplificationSuite extends PlanTest { class LikeSimplificationSuite extends PlanTest {
...@@ -100,4 +100,10 @@ class LikeSimplificationSuite extends PlanTest { ...@@ -100,4 +100,10 @@ class LikeSimplificationSuite extends PlanTest {
comparePlans(optimized, correctAnswer) comparePlans(optimized, correctAnswer)
} }
test("null pattern") {
val originalQuery = testRelation.where('a like Literal(null, StringType)).analyze
val optimized = Optimize.execute(originalQuery)
comparePlans(optimized, testRelation.where(Literal(null, BooleanType)).analyze)
}
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment