From 75d51ba2304e53d4a163f5fbade8ce325a0d3a0e Mon Sep 17 00:00:00 2001 From: wuyi Date: Mon, 11 Nov 2019 16:41:59 +0800 Subject: [PATCH 01/17] postgresql dialect: cast to boolean --- .../catalyst/analysis/PostgreSQLDialect.scala | 11 ++- .../spark/sql/catalyst/expressions/Cast.scala | 10 +-- .../PostgreCastStringToBoolean.scala | 80 ----------------- .../postgreSQL/PostgreCastToBoolean.scala | 85 +++++++++++++++++++ .../expressions/postgreSQL/CastSuite.scala | 73 +++++++++------- 5 files changed, 138 insertions(+), 121 deletions(-) delete mode 100644 sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/PostgreCastStringToBoolean.scala create mode 100644 sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/PostgreCastToBoolean.scala diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/PostgreSQLDialect.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/PostgreSQLDialect.scala index 934e53703e241..e9ad2caaa9786 100644 --- a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/PostgreSQLDialect.scala +++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/PostgreSQLDialect.scala @@ -19,7 +19,7 @@ package org.apache.spark.sql.catalyst.analysis import org.apache.spark.internal.Logging import org.apache.spark.sql.catalyst.expressions.Cast -import org.apache.spark.sql.catalyst.expressions.postgreSQL.PostgreCastStringToBoolean +import org.apache.spark.sql.catalyst.expressions.postgreSQL.PostgreCastToBoolean import org.apache.spark.sql.catalyst.plans.logical.LogicalPlan import org.apache.spark.sql.catalyst.rules.Rule import org.apache.spark.sql.internal.SQLConf @@ -27,19 +27,18 @@ import org.apache.spark.sql.types.{BooleanType, StringType} object PostgreSQLDialect { val postgreSQLDialectRules: List[Rule[LogicalPlan]] = - CastStringToBoolean :: + CastToBoolean :: Nil - object CastStringToBoolean extends Rule[LogicalPlan] with Logging { + object CastToBoolean extends Rule[LogicalPlan] with Logging { override def apply(plan: LogicalPlan): LogicalPlan = { // The SQL configuration `spark.sql.dialect` can be changed in runtime. // To make sure the configuration is effective, we have to check it during rule execution. val conf = SQLConf.get if (conf.usePostgreSQLDialect) { plan.transformExpressions { - case Cast(child, dataType, _) - if dataType == BooleanType && child.dataType == StringType => - PostgreCastStringToBoolean(child) + case Cast(child, dataType, timeZoneId) if dataType == BooleanType => + PostgreCastToBoolean(child, timeZoneId) } } else { plan diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/Cast.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/Cast.scala index 862b2bb515a19..f6b6be2aedc3c 100644 --- a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/Cast.scala +++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/Cast.scala @@ -273,7 +273,7 @@ abstract class CastBase extends UnaryExpression with TimeZoneAwareExpression wit private[this] def needsTimeZone: Boolean = Cast.needsTimeZone(child.dataType, dataType) // [[func]] assumes the input is no longer null because eval already does the null check. - @inline private[this] def buildCast[T](a: Any, func: T => Any): Any = func(a.asInstanceOf[T]) + @inline private[catalyst] def buildCast[T](a: Any, func: T => Any): Any = func(a.asInstanceOf[T]) private lazy val dateFormatter = DateFormatter(zoneId) private lazy val timestampFormatter = TimestampFormatter.getFractionFormatter(zoneId) @@ -376,7 +376,7 @@ abstract class CastBase extends UnaryExpression with TimeZoneAwareExpression wit } // UDFToBoolean - private[this] def castToBoolean(from: DataType): Any => Any = from match { + protected[this] def castToBoolean(from: DataType): Any => Any = from match { case StringType => buildCast[UTF8String](_, s => { if (StringUtils.isTrueString(s)) { @@ -781,7 +781,7 @@ abstract class CastBase extends UnaryExpression with TimeZoneAwareExpression wit } } - override def doGenCode(ctx: CodegenContext, ev: ExprCode): ExprCode = { + override protected def doGenCode(ctx: CodegenContext, ev: ExprCode): ExprCode = { val eval = child.genCode(ctx) val nullSafeCast = nullSafeCastFunction(child.dataType, dataType, ctx) @@ -791,7 +791,7 @@ abstract class CastBase extends UnaryExpression with TimeZoneAwareExpression wit // The function arguments are: `input`, `result` and `resultIsNull`. We don't need `inputIsNull` // in parameter list, because the returned code will be put in null safe evaluation region. - private[this] type CastFunction = (ExprValue, ExprValue, ExprValue) => Block + protected[this] type CastFunction = (ExprValue, ExprValue, ExprValue) => Block private[this] def nullSafeCastFunction( from: DataType, @@ -1233,7 +1233,7 @@ abstract class CastBase extends UnaryExpression with TimeZoneAwareExpression wit private[this] def timestampToDoubleCode(ts: ExprValue): Block = code"$ts / (double)$MICROS_PER_SECOND" - private[this] def castToBooleanCode(from: DataType): CastFunction = from match { + protected[this] def castToBooleanCode(from: DataType): CastFunction = from match { case StringType => val stringUtils = inline"${StringUtils.getClass.getName.stripSuffix("$")}" (c, evPrim, evNull) => diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/PostgreCastStringToBoolean.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/PostgreCastStringToBoolean.scala deleted file mode 100644 index 0e87707d01e47..0000000000000 --- a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/PostgreCastStringToBoolean.scala +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.spark.sql.catalyst.expressions.postgreSQL - -import org.apache.spark.sql.catalyst.analysis.TypeCheckResult -import org.apache.spark.sql.catalyst.expressions.{Expression, NullIntolerant, UnaryExpression} -import org.apache.spark.sql.catalyst.expressions.codegen.{CodegenContext, ExprCode, JavaCode} -import org.apache.spark.sql.catalyst.expressions.codegen.Block._ -import org.apache.spark.sql.catalyst.util.postgreSQL.StringUtils -import org.apache.spark.sql.types.{BooleanType, DataType, StringType} -import org.apache.spark.unsafe.types.UTF8String - -case class PostgreCastStringToBoolean(child: Expression) - extends UnaryExpression with NullIntolerant { - - override def checkInputDataTypes(): TypeCheckResult = { - if (child.dataType == StringType) { - TypeCheckResult.TypeCheckSuccess - } else { - TypeCheckResult.TypeCheckFailure( - s"The expression ${getClass.getSimpleName} only accepts string input data type") - } - } - - override def nullSafeEval(input: Any): Any = { - val s = input.asInstanceOf[UTF8String].trim().toLowerCase() - if (StringUtils.isTrueString(s)) { - true - } else if (StringUtils.isFalseString(s)) { - false - } else { - null - } - } - - override protected def doGenCode(ctx: CodegenContext, ev: ExprCode): ExprCode = { - val stringUtils = inline"${StringUtils.getClass.getName.stripSuffix("$")}" - val eval = child.genCode(ctx) - val javaType = JavaCode.javaType(dataType) - val preprocessedString = ctx.freshName("preprocessedString") - val castCode = - code""" - boolean ${ev.isNull} = ${eval.isNull}; - $javaType ${ev.value} = false; - if (!${eval.isNull}) { - UTF8String $preprocessedString = ${eval.value}.trim().toLowerCase(); - if ($stringUtils.isTrueString($preprocessedString)) { - ${ev.value} = true; - } else if ($stringUtils.isFalseString($preprocessedString)) { - ${ev.value} = false; - } else { - ${ev.isNull} = true; - } - } - """ - ev.copy(code = eval.code + castCode) - } - - override def dataType: DataType = BooleanType - - override def nullable: Boolean = true - - override def toString: String = s"PostgreCastStringToBoolean($child as ${dataType.simpleString})" - - override def sql: String = s"CAST(${child.sql} AS ${dataType.sql})" -} diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/PostgreCastToBoolean.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/PostgreCastToBoolean.scala new file mode 100644 index 0000000000000..55391ae101785 --- /dev/null +++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/PostgreCastToBoolean.scala @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.spark.sql.catalyst.expressions.postgreSQL + +import org.apache.spark.sql.catalyst.expressions.{CastBase, Expression, TimeZoneAwareExpression} +import org.apache.spark.sql.catalyst.expressions.codegen.Block._ +import org.apache.spark.sql.catalyst.expressions.codegen.JavaCode +import org.apache.spark.sql.catalyst.util.postgreSQL.StringUtils +import org.apache.spark.sql.internal.SQLConf +import org.apache.spark.sql.types._ +import org.apache.spark.unsafe.types.UTF8String + +case class PostgreCastToBoolean(child: Expression, timeZoneId: Option[String]) + extends CastBase { + + override protected def ansiEnabled = SQLConf.get.ansiEnabled + + override def withTimeZone(timeZoneId: String): TimeZoneAwareExpression = + copy(timeZoneId = Option(timeZoneId)) + + override def castToBoolean(from: DataType): Any => Any = from match { + case StringType => + buildCast[UTF8String](_, str => { + val s = str.trim().toLowerCase() + if (StringUtils.isTrueString(s)) { + true + } else if (StringUtils.isFalseString(s)) { + false + } else { + throw new IllegalArgumentException(s"invalid input syntax for type boolean: $s") + } + }) + case TimestampType | DateType | LongType | ShortType | + ByteType | DecimalType() | DoubleType | FloatType => + _ => throw new UnsupportedOperationException(s"cannot cast type $from to boolean") + + case IntegerType => + super.castToBoolean(from) + } + + override def castToBooleanCode(from: DataType): CastFunction = from match { + case StringType => + val stringUtils = inline"${StringUtils.getClass.getName.stripSuffix("$")}" + (c, evPrim, evNull) => + code""" + if ($stringUtils.isTrueString($c.trim().toLowerCase())) { + $evPrim = true; + } else if ($stringUtils.isFalseString($c.trim().toLowerCase())) { + $evPrim = false; + } else { + throw new IllegalArgumentException("invalid input syntax for type boolean: $c"); + } + """ + case TimestampType | DateType | LongType | ShortType | + ByteType | DecimalType() | DoubleType | FloatType => + (c, evPrim, evNull) => + val fromType = JavaCode.javaType(from) + code"""throw new UnsupportedOperationException("cannot cast type $fromType to boolean");""" + + case IntegerType => + super.castToBooleanCode(from) + } + + override def dataType: DataType = BooleanType + + override def nullable: Boolean = true + + override def toString: String = s"PostgreCastToBoolean($child as ${dataType.simpleString})" + + override def sql: String = s"CAST(${child.sql} AS ${dataType.sql})" +} diff --git a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/CastSuite.scala b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/CastSuite.scala index 175904da21969..0030db8f8ef88 100644 --- a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/CastSuite.scala +++ b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/CastSuite.scala @@ -16,44 +16,57 @@ */ package org.apache.spark.sql.catalyst.expressions.postgreSQL +import java.sql.{Date, Timestamp} + import org.apache.spark.SparkFunSuite import org.apache.spark.sql.catalyst.expressions.{ExpressionEvalHelper, Literal} class CastSuite extends SparkFunSuite with ExpressionEvalHelper { - private def checkPostgreCastStringToBoolean(v: Any, expected: Any): Unit = { - checkEvaluation(PostgreCastStringToBoolean(Literal(v)), expected) + private def checkPostgreCastToBoolean(v: Any, expected: Any): Unit = { + checkEvaluation(PostgreCastToBoolean(Literal(v), None), expected) } test("cast string to boolean") { - checkPostgreCastStringToBoolean("true", true) - checkPostgreCastStringToBoolean("tru", true) - checkPostgreCastStringToBoolean("tr", true) - checkPostgreCastStringToBoolean("t", true) - checkPostgreCastStringToBoolean("tRUe", true) - checkPostgreCastStringToBoolean(" tRue ", true) - checkPostgreCastStringToBoolean(" tRu ", true) - checkPostgreCastStringToBoolean("yes", true) - checkPostgreCastStringToBoolean("ye", true) - checkPostgreCastStringToBoolean("y", true) - checkPostgreCastStringToBoolean("1", true) - checkPostgreCastStringToBoolean("on", true) + checkPostgreCastToBoolean("true", true) + checkPostgreCastToBoolean("tru", true) + checkPostgreCastToBoolean("tr", true) + checkPostgreCastToBoolean("t", true) + checkPostgreCastToBoolean("tRUe", true) + checkPostgreCastToBoolean(" tRue ", true) + checkPostgreCastToBoolean(" tRu ", true) + checkPostgreCastToBoolean("yes", true) + checkPostgreCastToBoolean("ye", true) + checkPostgreCastToBoolean("y", true) + checkPostgreCastToBoolean("1", true) + checkPostgreCastToBoolean("on", true) + + checkPostgreCastToBoolean("false", false) + checkPostgreCastToBoolean("fals", false) + checkPostgreCastToBoolean("fal", false) + checkPostgreCastToBoolean("fa", false) + checkPostgreCastToBoolean("f", false) + checkPostgreCastToBoolean(" fAlse ", false) + checkPostgreCastToBoolean(" fAls ", false) + checkPostgreCastToBoolean(" FAlsE ", false) + checkPostgreCastToBoolean("no", false) + checkPostgreCastToBoolean("n", false) + checkPostgreCastToBoolean("0", false) + checkPostgreCastToBoolean("off", false) + checkPostgreCastToBoolean("of", false) - checkPostgreCastStringToBoolean("false", false) - checkPostgreCastStringToBoolean("fals", false) - checkPostgreCastStringToBoolean("fal", false) - checkPostgreCastStringToBoolean("fa", false) - checkPostgreCastStringToBoolean("f", false) - checkPostgreCastStringToBoolean(" fAlse ", false) - checkPostgreCastStringToBoolean(" fAls ", false) - checkPostgreCastStringToBoolean(" FAlsE ", false) - checkPostgreCastStringToBoolean("no", false) - checkPostgreCastStringToBoolean("n", false) - checkPostgreCastStringToBoolean("0", false) - checkPostgreCastStringToBoolean("off", false) - checkPostgreCastStringToBoolean("of", false) + intercept[Exception](checkPostgreCastToBoolean("o", null)) + intercept[Exception](checkPostgreCastToBoolean("abc", null)) + intercept[Exception](checkPostgreCastToBoolean("", null)) + } - checkPostgreCastStringToBoolean("o", null) - checkPostgreCastStringToBoolean("abc", null) - checkPostgreCastStringToBoolean("", null) + test("unsupported data types to cast to boolean") { + intercept[Exception](checkPostgreCastToBoolean(new Timestamp(1), null)) + intercept[Exception](checkPostgreCastToBoolean(new Date(1), null)) + intercept[Exception](checkPostgreCastToBoolean(1.toLong, null)) + intercept[Exception](checkPostgreCastToBoolean(1.toShort, null)) + intercept[Exception](checkPostgreCastToBoolean(1.toByte, null)) + intercept[Exception](checkPostgreCastToBoolean(BigDecimal(1.0), null)) + intercept[Exception](checkPostgreCastToBoolean(1.toDouble, null)) + intercept[Exception](checkPostgreCastToBoolean(1.toFloat, null)) } } From 53c9a9bb66accb289af1a9c7163519fe72c3b85a Mon Sep 17 00:00:00 2001 From: wuyi Date: Mon, 11 Nov 2019 20:56:26 +0800 Subject: [PATCH 02/17] fix PostgreSQLDialectQuerySuite --- .../org/apache/spark/sql/PostgreSQLDialectQuerySuite.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sql/core/src/test/scala/org/apache/spark/sql/PostgreSQLDialectQuerySuite.scala b/sql/core/src/test/scala/org/apache/spark/sql/PostgreSQLDialectQuerySuite.scala index 1354dcfda45fe..b8f388cac1aae 100644 --- a/sql/core/src/test/scala/org/apache/spark/sql/PostgreSQLDialectQuerySuite.scala +++ b/sql/core/src/test/scala/org/apache/spark/sql/PostgreSQLDialectQuerySuite.scala @@ -36,7 +36,8 @@ class PostgreSQLDialectQuerySuite extends QueryTest with SharedSparkSession { } Seq("o", "abc", "").foreach { input => - checkAnswer(sql(s"select cast('$input' as boolean)"), Row(null)) + intercept[IllegalArgumentException]( + checkAnswer(sql(s"select cast('$input' as boolean)"), Row(null))) } } } From 2ab1847afa74da88bd4764d084acd255f7563258 Mon Sep 17 00:00:00 2001 From: wuyi Date: Mon, 11 Nov 2019 21:30:26 +0800 Subject: [PATCH 03/17] fix postgreSQL/boolean.sql --- .../results/postgreSQL/boolean.sql.out | 60 +++++++++++-------- 1 file changed, 36 insertions(+), 24 deletions(-) diff --git a/sql/core/src/test/resources/sql-tests/results/postgreSQL/boolean.sql.out b/sql/core/src/test/resources/sql-tests/results/postgreSQL/boolean.sql.out index 203806d43368a..e5f3425efc458 100644 --- a/sql/core/src/test/resources/sql-tests/results/postgreSQL/boolean.sql.out +++ b/sql/core/src/test/resources/sql-tests/results/postgreSQL/boolean.sql.out @@ -53,9 +53,10 @@ true -- !query 6 SELECT boolean('test') AS error -- !query 6 schema -struct +struct<> -- !query 6 output -NULL +java.lang.IllegalArgumentException +invalid input syntax for type boolean: test -- !query 7 @@ -69,9 +70,10 @@ false -- !query 8 SELECT boolean('foo') AS error -- !query 8 schema -struct +struct<> -- !query 8 output -NULL +java.lang.IllegalArgumentException +invalid input syntax for type boolean: foo -- !query 9 @@ -93,9 +95,10 @@ true -- !query 11 SELECT boolean('yeah') AS error -- !query 11 schema -struct +struct<> -- !query 11 output -NULL +java.lang.IllegalArgumentException +invalid input syntax for type boolean: yeah -- !query 12 @@ -117,9 +120,10 @@ false -- !query 14 SELECT boolean('nay') AS error -- !query 14 schema -struct +struct<> -- !query 14 output -NULL +java.lang.IllegalArgumentException +invalid input syntax for type boolean: nay -- !query 15 @@ -149,25 +153,28 @@ false -- !query 18 SELECT boolean('o') AS error -- !query 18 schema -struct +struct<> -- !query 18 output -NULL +java.lang.IllegalArgumentException +invalid input syntax for type boolean: o -- !query 19 SELECT boolean('on_') AS error -- !query 19 schema -struct +struct<> -- !query 19 output -NULL +java.lang.IllegalArgumentException +invalid input syntax for type boolean: on_ -- !query 20 SELECT boolean('off_') AS error -- !query 20 schema -struct +struct<> -- !query 20 output -NULL +java.lang.IllegalArgumentException +invalid input syntax for type boolean: off_ -- !query 21 @@ -181,9 +188,10 @@ true -- !query 22 SELECT boolean('11') AS error -- !query 22 schema -struct +struct<> -- !query 22 output -NULL +java.lang.IllegalArgumentException +invalid input syntax for type boolean: 11 -- !query 23 @@ -197,17 +205,19 @@ false -- !query 24 SELECT boolean('000') AS error -- !query 24 schema -struct +struct<> -- !query 24 output -NULL +java.lang.IllegalArgumentException +invalid input syntax for type boolean: 000 -- !query 25 SELECT boolean('') AS error -- !query 25 schema -struct +struct<> -- !query 25 output -NULL +java.lang.IllegalArgumentException +invalid input syntax for type boolean: -- !query 26 @@ -310,17 +320,19 @@ true false -- !query 38 SELECT boolean(string(' tru e ')) AS invalid -- !query 38 schema -struct +struct<> -- !query 38 output -NULL +java.lang.IllegalArgumentException +invalid input syntax for type boolean: tru e -- !query 39 SELECT boolean(string('')) AS invalid -- !query 39 schema -struct +struct<> -- !query 39 output -NULL +java.lang.IllegalArgumentException +invalid input syntax for type boolean: -- !query 40 From 6c2c0c71a06c4d07d07b538044aef25006062789 Mon Sep 17 00:00:00 2001 From: wuyi Date: Tue, 12 Nov 2019 10:08:13 +0800 Subject: [PATCH 04/17] nullable should be false now --- .../catalyst/expressions/postgreSQL/PostgreCastToBoolean.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/PostgreCastToBoolean.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/PostgreCastToBoolean.scala index 55391ae101785..294a5882c78fc 100644 --- a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/PostgreCastToBoolean.scala +++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/PostgreCastToBoolean.scala @@ -77,7 +77,7 @@ case class PostgreCastToBoolean(child: Expression, timeZoneId: Option[String]) override def dataType: DataType = BooleanType - override def nullable: Boolean = true + override def nullable: Boolean = false override def toString: String = s"PostgreCastToBoolean($child as ${dataType.simpleString})" From 6ad100c921ed6f1e52c2e191cced400b3a335206 Mon Sep 17 00:00:00 2001 From: wuyi Date: Tue, 12 Nov 2019 10:22:09 +0800 Subject: [PATCH 05/17] check unsupported types in checkInputDataTypes() --- .../postgreSQL/PostgreCastToBoolean.scala | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/PostgreCastToBoolean.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/PostgreCastToBoolean.scala index 294a5882c78fc..89b074d406abd 100644 --- a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/PostgreCastToBoolean.scala +++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/PostgreCastToBoolean.scala @@ -16,6 +16,7 @@ */ package org.apache.spark.sql.catalyst.expressions.postgreSQL +import org.apache.spark.sql.catalyst.analysis.TypeCheckResult import org.apache.spark.sql.catalyst.expressions.{CastBase, Expression, TimeZoneAwareExpression} import org.apache.spark.sql.catalyst.expressions.codegen.Block._ import org.apache.spark.sql.catalyst.expressions.codegen.JavaCode @@ -32,6 +33,11 @@ case class PostgreCastToBoolean(child: Expression, timeZoneId: Option[String]) override def withTimeZone(timeZoneId: String): TimeZoneAwareExpression = copy(timeZoneId = Option(timeZoneId)) + override def checkInputDataTypes(): TypeCheckResult = child.dataType match { + case StringType | IntegerType => super.checkInputDataTypes() + case dt => throw new UnsupportedOperationException(s"cannot cast type $dt to boolean") + } + override def castToBoolean(from: DataType): Any => Any = from match { case StringType => buildCast[UTF8String](_, str => { @@ -44,10 +50,6 @@ case class PostgreCastToBoolean(child: Expression, timeZoneId: Option[String]) throw new IllegalArgumentException(s"invalid input syntax for type boolean: $s") } }) - case TimestampType | DateType | LongType | ShortType | - ByteType | DecimalType() | DoubleType | FloatType => - _ => throw new UnsupportedOperationException(s"cannot cast type $from to boolean") - case IntegerType => super.castToBoolean(from) } @@ -65,11 +67,6 @@ case class PostgreCastToBoolean(child: Expression, timeZoneId: Option[String]) throw new IllegalArgumentException("invalid input syntax for type boolean: $c"); } """ - case TimestampType | DateType | LongType | ShortType | - ByteType | DecimalType() | DoubleType | FloatType => - (c, evPrim, evNull) => - val fromType = JavaCode.javaType(from) - code"""throw new UnsupportedOperationException("cannot cast type $fromType to boolean");""" case IntegerType => super.castToBooleanCode(from) From 101a0267385ce1de4e75aaa29c87013facade28a Mon Sep 17 00:00:00 2001 From: wuyi Date: Tue, 12 Nov 2019 14:27:18 +0800 Subject: [PATCH 06/17] private[catalyst] -> protected[this] --- .../scala/org/apache/spark/sql/catalyst/expressions/Cast.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/Cast.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/Cast.scala index f6b6be2aedc3c..122106b57fab3 100644 --- a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/Cast.scala +++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/Cast.scala @@ -273,7 +273,7 @@ abstract class CastBase extends UnaryExpression with TimeZoneAwareExpression wit private[this] def needsTimeZone: Boolean = Cast.needsTimeZone(child.dataType, dataType) // [[func]] assumes the input is no longer null because eval already does the null check. - @inline private[catalyst] def buildCast[T](a: Any, func: T => Any): Any = func(a.asInstanceOf[T]) + @inline protected[this] def buildCast[T](a: Any, func: T => Any): Any = func(a.asInstanceOf[T]) private lazy val dateFormatter = DateFormatter(zoneId) private lazy val timestampFormatter = TimestampFormatter.getFractionFormatter(zoneId) From be08daf0a9bff6d583f3b8ff9d40d83c4e3359b7 Mon Sep 17 00:00:00 2001 From: wuyi Date: Tue, 12 Nov 2019 14:27:44 +0800 Subject: [PATCH 07/17] remove unused import --- .../catalyst/expressions/postgreSQL/PostgreCastToBoolean.scala | 1 - 1 file changed, 1 deletion(-) diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/PostgreCastToBoolean.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/PostgreCastToBoolean.scala index 89b074d406abd..5d4c02df5ca27 100644 --- a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/PostgreCastToBoolean.scala +++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/PostgreCastToBoolean.scala @@ -19,7 +19,6 @@ package org.apache.spark.sql.catalyst.expressions.postgreSQL import org.apache.spark.sql.catalyst.analysis.TypeCheckResult import org.apache.spark.sql.catalyst.expressions.{CastBase, Expression, TimeZoneAwareExpression} import org.apache.spark.sql.catalyst.expressions.codegen.Block._ -import org.apache.spark.sql.catalyst.expressions.codegen.JavaCode import org.apache.spark.sql.catalyst.util.postgreSQL.StringUtils import org.apache.spark.sql.internal.SQLConf import org.apache.spark.sql.types._ From 95caf40b494091ccab88e2d1b6a1cd7103361998 Mon Sep 17 00:00:00 2001 From: wuyi Date: Tue, 12 Nov 2019 14:28:42 +0800 Subject: [PATCH 08/17] return TypeCheckSuccess --- .../catalyst/expressions/postgreSQL/PostgreCastToBoolean.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/PostgreCastToBoolean.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/PostgreCastToBoolean.scala index 5d4c02df5ca27..65815131f4d3a 100644 --- a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/PostgreCastToBoolean.scala +++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/PostgreCastToBoolean.scala @@ -33,7 +33,7 @@ case class PostgreCastToBoolean(child: Expression, timeZoneId: Option[String]) copy(timeZoneId = Option(timeZoneId)) override def checkInputDataTypes(): TypeCheckResult = child.dataType match { - case StringType | IntegerType => super.checkInputDataTypes() + case StringType | IntegerType => TypeCheckResult.TypeCheckSuccess case dt => throw new UnsupportedOperationException(s"cannot cast type $dt to boolean") } From 8ebd5aab661791c9b2631be38d9282eb1d438a09 Mon Sep 17 00:00:00 2001 From: wuyi Date: Tue, 12 Nov 2019 15:23:56 +0800 Subject: [PATCH 09/17] use collect() --- .../org/apache/spark/sql/PostgreSQLDialectQuerySuite.scala | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sql/core/src/test/scala/org/apache/spark/sql/PostgreSQLDialectQuerySuite.scala b/sql/core/src/test/scala/org/apache/spark/sql/PostgreSQLDialectQuerySuite.scala index b8f388cac1aae..7056f483609a9 100644 --- a/sql/core/src/test/scala/org/apache/spark/sql/PostgreSQLDialectQuerySuite.scala +++ b/sql/core/src/test/scala/org/apache/spark/sql/PostgreSQLDialectQuerySuite.scala @@ -36,8 +36,7 @@ class PostgreSQLDialectQuerySuite extends QueryTest with SharedSparkSession { } Seq("o", "abc", "").foreach { input => - intercept[IllegalArgumentException]( - checkAnswer(sql(s"select cast('$input' as boolean)"), Row(null))) + intercept[IllegalArgumentException](sql(s"select cast('$input' as boolean)").collect()) } } } From 0b9a78dc9fa2923586816acab89a5ddf20913397 Mon Sep 17 00:00:00 2001 From: wuyi Date: Tue, 12 Nov 2019 15:32:53 +0800 Subject: [PATCH 10/17] use child.nullable --- .../catalyst/expressions/postgreSQL/PostgreCastToBoolean.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/PostgreCastToBoolean.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/PostgreCastToBoolean.scala index 65815131f4d3a..5f3f59ca4c3b1 100644 --- a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/PostgreCastToBoolean.scala +++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/PostgreCastToBoolean.scala @@ -73,7 +73,7 @@ case class PostgreCastToBoolean(child: Expression, timeZoneId: Option[String]) override def dataType: DataType = BooleanType - override def nullable: Boolean = false + override def nullable: Boolean = child.nullable override def toString: String = s"PostgreCastToBoolean($child as ${dataType.simpleString})" From fda48c01677fec3df73442d5a83a5f53c8e0fb08 Mon Sep 17 00:00:00 2001 From: wuyi Date: Tue, 12 Nov 2019 19:20:34 +0800 Subject: [PATCH 11/17] excludes unsupported types explicitly --- .../expressions/postgreSQL/PostgreCastToBoolean.scala | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/PostgreCastToBoolean.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/PostgreCastToBoolean.scala index 5f3f59ca4c3b1..9c75450b4bf25 100644 --- a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/PostgreCastToBoolean.scala +++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/PostgreCastToBoolean.scala @@ -33,8 +33,10 @@ case class PostgreCastToBoolean(child: Expression, timeZoneId: Option[String]) copy(timeZoneId = Option(timeZoneId)) override def checkInputDataTypes(): TypeCheckResult = child.dataType match { - case StringType | IntegerType => TypeCheckResult.TypeCheckSuccess - case dt => throw new UnsupportedOperationException(s"cannot cast type $dt to boolean") + case TimestampType | DateType | LongType | ShortType | + ByteType | DecimalType() | DoubleType | FloatType => + TypeCheckResult.TypeCheckFailure(s"cannot cast type ${child.dataType} to boolean") + case _ => TypeCheckResult.TypeCheckSuccess } override def castToBoolean(from: DataType): Any => Any = from match { From 36f60ee940c4fdde5fa668e93a3536c6ddd8f07c Mon Sep 17 00:00:00 2001 From: wuyi Date: Tue, 12 Nov 2019 19:22:12 +0800 Subject: [PATCH 12/17] protected[this] -> protected --- .../org/apache/spark/sql/catalyst/expressions/Cast.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/Cast.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/Cast.scala index 122106b57fab3..322695036592c 100644 --- a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/Cast.scala +++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/Cast.scala @@ -273,7 +273,7 @@ abstract class CastBase extends UnaryExpression with TimeZoneAwareExpression wit private[this] def needsTimeZone: Boolean = Cast.needsTimeZone(child.dataType, dataType) // [[func]] assumes the input is no longer null because eval already does the null check. - @inline protected[this] def buildCast[T](a: Any, func: T => Any): Any = func(a.asInstanceOf[T]) + @inline protected def buildCast[T](a: Any, func: T => Any): Any = func(a.asInstanceOf[T]) private lazy val dateFormatter = DateFormatter(zoneId) private lazy val timestampFormatter = TimestampFormatter.getFractionFormatter(zoneId) @@ -791,7 +791,7 @@ abstract class CastBase extends UnaryExpression with TimeZoneAwareExpression wit // The function arguments are: `input`, `result` and `resultIsNull`. We don't need `inputIsNull` // in parameter list, because the returned code will be put in null safe evaluation region. - protected[this] type CastFunction = (ExprValue, ExprValue, ExprValue) => Block + protected type CastFunction = (ExprValue, ExprValue, ExprValue) => Block private[this] def nullSafeCastFunction( from: DataType, From b7c6bafb74a622653599911fa44f3ba01daf91bf Mon Sep 17 00:00:00 2001 From: wuyi Date: Tue, 12 Nov 2019 19:24:49 +0800 Subject: [PATCH 13/17] throw exception for PostgreCastToBoolean.ansiEnabled --- .../expressions/postgreSQL/PostgreCastToBoolean.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/PostgreCastToBoolean.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/PostgreCastToBoolean.scala index 9c75450b4bf25..b8834dbfa7e6d 100644 --- a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/PostgreCastToBoolean.scala +++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/PostgreCastToBoolean.scala @@ -20,14 +20,14 @@ import org.apache.spark.sql.catalyst.analysis.TypeCheckResult import org.apache.spark.sql.catalyst.expressions.{CastBase, Expression, TimeZoneAwareExpression} import org.apache.spark.sql.catalyst.expressions.codegen.Block._ import org.apache.spark.sql.catalyst.util.postgreSQL.StringUtils -import org.apache.spark.sql.internal.SQLConf import org.apache.spark.sql.types._ import org.apache.spark.unsafe.types.UTF8String case class PostgreCastToBoolean(child: Expression, timeZoneId: Option[String]) extends CastBase { - override protected def ansiEnabled = SQLConf.get.ansiEnabled + override protected def ansiEnabled = + throw new UnsupportedOperationException("PostgreSQL dialect doesn't support ansi mode") override def withTimeZone(timeZoneId: String): TimeZoneAwareExpression = copy(timeZoneId = Option(timeZoneId)) From b9711ae86c51eb7f7db1e1f1724f2407186c270d Mon Sep 17 00:00:00 2001 From: wuyi Date: Wed, 13 Nov 2019 10:43:53 +0800 Subject: [PATCH 14/17] include supportted types explicitly --- .../expressions/postgreSQL/PostgreCastToBoolean.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/PostgreCastToBoolean.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/PostgreCastToBoolean.scala index b8834dbfa7e6d..20559ba3cd79e 100644 --- a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/PostgreCastToBoolean.scala +++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/PostgreCastToBoolean.scala @@ -33,10 +33,10 @@ case class PostgreCastToBoolean(child: Expression, timeZoneId: Option[String]) copy(timeZoneId = Option(timeZoneId)) override def checkInputDataTypes(): TypeCheckResult = child.dataType match { - case TimestampType | DateType | LongType | ShortType | - ByteType | DecimalType() | DoubleType | FloatType => + case StringType | IntegerType | NullType => + TypeCheckResult.TypeCheckSuccess + case _ => TypeCheckResult.TypeCheckFailure(s"cannot cast type ${child.dataType} to boolean") - case _ => TypeCheckResult.TypeCheckSuccess } override def castToBoolean(from: DataType): Any => Any = from match { From 68c7a133b888b3a2fecb7662fc6424dac0a03b8e Mon Sep 17 00:00:00 2001 From: wuyi Date: Wed, 13 Nov 2019 15:21:30 +0800 Subject: [PATCH 15/17] adjust tests --- .../expressions/postgreSQL/CastSuite.scala | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/CastSuite.scala b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/CastSuite.scala index 0030db8f8ef88..6c5218b379f31 100644 --- a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/CastSuite.scala +++ b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/CastSuite.scala @@ -19,6 +19,7 @@ package org.apache.spark.sql.catalyst.expressions.postgreSQL import java.sql.{Date, Timestamp} import org.apache.spark.SparkFunSuite +import org.apache.spark.sql.AnalysisException import org.apache.spark.sql.catalyst.expressions.{ExpressionEvalHelper, Literal} class CastSuite extends SparkFunSuite with ExpressionEvalHelper { @@ -54,19 +55,19 @@ class CastSuite extends SparkFunSuite with ExpressionEvalHelper { checkPostgreCastToBoolean("off", false) checkPostgreCastToBoolean("of", false) - intercept[Exception](checkPostgreCastToBoolean("o", null)) - intercept[Exception](checkPostgreCastToBoolean("abc", null)) - intercept[Exception](checkPostgreCastToBoolean("", null)) + intercept[IllegalArgumentException](PostgreCastToBoolean(Literal("o"), None).eval()) + intercept[IllegalArgumentException](PostgreCastToBoolean(Literal("abc"), None).eval()) + intercept[IllegalArgumentException](PostgreCastToBoolean(Literal(""), None).eval()) } test("unsupported data types to cast to boolean") { - intercept[Exception](checkPostgreCastToBoolean(new Timestamp(1), null)) - intercept[Exception](checkPostgreCastToBoolean(new Date(1), null)) - intercept[Exception](checkPostgreCastToBoolean(1.toLong, null)) - intercept[Exception](checkPostgreCastToBoolean(1.toShort, null)) - intercept[Exception](checkPostgreCastToBoolean(1.toByte, null)) - intercept[Exception](checkPostgreCastToBoolean(BigDecimal(1.0), null)) - intercept[Exception](checkPostgreCastToBoolean(1.toDouble, null)) - intercept[Exception](checkPostgreCastToBoolean(1.toFloat, null)) + assert(PostgreCastToBoolean(Literal(new Timestamp(1)), None).checkInputDataTypes().isFailure) + assert(PostgreCastToBoolean(Literal(new Date(1)), None).checkInputDataTypes().isFailure) + assert(PostgreCastToBoolean(Literal(1.toLong), None).checkInputDataTypes().isFailure) + assert(PostgreCastToBoolean(Literal(1.toShort), None).checkInputDataTypes().isFailure) + assert(PostgreCastToBoolean(Literal(1.toByte), None).checkInputDataTypes().isFailure) + assert(PostgreCastToBoolean(Literal(BigDecimal(1.0)), None).checkInputDataTypes().isFailure) + assert(PostgreCastToBoolean(Literal(1.toDouble), None).checkInputDataTypes().isFailure) + assert(PostgreCastToBoolean(Literal(1.toFloat), None).checkInputDataTypes().isFailure) } } From 999ec61c4a55b938070adb664b21fd68da2b5f05 Mon Sep 17 00:00:00 2001 From: wuyi Date: Wed, 13 Nov 2019 21:46:43 +0800 Subject: [PATCH 16/17] missing BooleanType --- .../catalyst/expressions/postgreSQL/PostgreCastToBoolean.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/PostgreCastToBoolean.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/PostgreCastToBoolean.scala index 20559ba3cd79e..c654efab08cd7 100644 --- a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/PostgreCastToBoolean.scala +++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/PostgreCastToBoolean.scala @@ -33,7 +33,7 @@ case class PostgreCastToBoolean(child: Expression, timeZoneId: Option[String]) copy(timeZoneId = Option(timeZoneId)) override def checkInputDataTypes(): TypeCheckResult = child.dataType match { - case StringType | IntegerType | NullType => + case BooleanType | StringType | IntegerType | NullType => TypeCheckResult.TypeCheckSuccess case _ => TypeCheckResult.TypeCheckFailure(s"cannot cast type ${child.dataType} to boolean") From a178b79864cde4b8fa57913b5fe3d73084741c35 Mon Sep 17 00:00:00 2001 From: wuyi Date: Wed, 13 Nov 2019 22:12:20 +0800 Subject: [PATCH 17/17] leave cast( bool as bool) to optimizer --- .../apache/spark/sql/catalyst/analysis/PostgreSQLDialect.scala | 3 ++- .../catalyst/expressions/postgreSQL/PostgreCastToBoolean.scala | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/PostgreSQLDialect.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/PostgreSQLDialect.scala index e9ad2caaa9786..e7f0e571804d3 100644 --- a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/PostgreSQLDialect.scala +++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/PostgreSQLDialect.scala @@ -37,7 +37,8 @@ object PostgreSQLDialect { val conf = SQLConf.get if (conf.usePostgreSQLDialect) { plan.transformExpressions { - case Cast(child, dataType, timeZoneId) if dataType == BooleanType => + case Cast(child, dataType, timeZoneId) + if child.dataType != BooleanType && dataType == BooleanType => PostgreCastToBoolean(child, timeZoneId) } } else { diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/PostgreCastToBoolean.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/PostgreCastToBoolean.scala index c654efab08cd7..20559ba3cd79e 100644 --- a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/PostgreCastToBoolean.scala +++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/postgreSQL/PostgreCastToBoolean.scala @@ -33,7 +33,7 @@ case class PostgreCastToBoolean(child: Expression, timeZoneId: Option[String]) copy(timeZoneId = Option(timeZoneId)) override def checkInputDataTypes(): TypeCheckResult = child.dataType match { - case BooleanType | StringType | IntegerType | NullType => + case StringType | IntegerType | NullType => TypeCheckResult.TypeCheckSuccess case _ => TypeCheckResult.TypeCheckFailure(s"cannot cast type ${child.dataType} to boolean")