diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/SqlParser.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/SqlParser.scala index 79f526e823cd4..8bc78ac67d88f 100644 --- a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/SqlParser.scala +++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/SqlParser.scala @@ -207,7 +207,12 @@ class SqlParser extends AbstractSparkSQLParser with DataTypeParser { andExpression * (OR ^^^ { (e1: Expression, e2: Expression) => Or(e1, e2) }) protected lazy val andExpression: Parser[Expression] = - comparisonExpression * (AND ^^^ { (e1: Expression, e2: Expression) => And(e1, e2) }) + booleanFactor * (AND ^^^ { (e1: Expression, e2: Expression) => And(e1, e2) }) + + protected lazy val booleanFactor: Parser[Expression] = + NOT.? ~ comparisonExpression ^^ { + case notOpt ~ expr => notOpt.map(s => Not(expr)).getOrElse(expr) + } protected lazy val comparisonExpression: Parser[Expression] = ( termExpression ~ ("=" ~> termExpression) ^^ { case e1 ~ e2 => EqualTo(e1, e2) } @@ -235,7 +240,6 @@ class SqlParser extends AbstractSparkSQLParser with DataTypeParser { } | termExpression <~ IS ~ NULL ^^ { case e => IsNull(e) } | termExpression <~ IS ~ NOT ~ NULL ^^ { case e => IsNotNull(e) } - | NOT ~> termExpression ^^ {e => Not(e)} | termExpression ) diff --git a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/SqlParserSuite.scala b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/SqlParserSuite.scala index b93a3abc6ebd2..e33d34078ea27 100644 --- a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/SqlParserSuite.scala +++ b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/SqlParserSuite.scala @@ -18,7 +18,10 @@ package org.apache.spark.sql.catalyst import org.apache.spark.SparkFunSuite +import org.apache.spark.sql.catalyst.analysis.{UnresolvedStar, UnresolvedRelation} import org.apache.spark.sql.catalyst.expressions.Attribute +import org.apache.spark.sql.catalyst.dsl.expressions._ +import org.apache.spark.sql.catalyst.dsl.plans._ import org.apache.spark.sql.catalyst.plans.logical.LogicalPlan import org.apache.spark.sql.catalyst.plans.logical.Command @@ -51,6 +54,15 @@ private[sql] class CaseInsensitiveTestParser extends AbstractSparkSQLParser { class SqlParserSuite extends SparkFunSuite { + test("precedence of NOT operator") { + val parser = new SqlParser + val actual = parser.parse("SELECT * FROM t WHERE NOT c IS NULL") + val expected = UnresolvedRelation("t" :: Nil) + .where('c.isNull.unary_!) + .select(UnresolvedStar(None)) + assertResult(expected)(actual) + } + test("test long keyword") { val parser = new SuperLongKeywordTestParser assert(TestCommand("NotRealCommand") ===