Skip to content

Commit 732b9fe

Browse files
authored
fix: Support concat_ws with literal NULL separator (#3542)
1 parent 5c1f131 commit 732b9fe

3 files changed

Lines changed: 25 additions & 4 deletions

File tree

spark/src/main/scala/org/apache/comet/serde/QueryPlanSerde.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ object QueryPlanSerde extends Logging with CometExprShim {
149149
classOf[Ascii] -> CometScalarFunction("ascii"),
150150
classOf[BitLength] -> CometScalarFunction("bit_length"),
151151
classOf[Chr] -> CometScalarFunction("char"),
152-
classOf[ConcatWs] -> CometScalarFunction("concat_ws"),
152+
classOf[ConcatWs] -> CometConcatWs,
153153
classOf[Concat] -> CometConcat,
154154
classOf[Contains] -> CometScalarFunction("contains"),
155155
classOf[EndsWith] -> CometScalarFunction("ends_with"),

spark/src/main/scala/org/apache/comet/serde/strings.scala

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ package org.apache.comet.serde
2121

2222
import java.util.Locale
2323

24-
import org.apache.spark.sql.catalyst.expressions.{Attribute, Cast, Concat, Expression, If, InitCap, IsNull, Left, Length, Like, Literal, Lower, RegExpReplace, Right, RLike, StringLPad, StringRepeat, StringRPad, StringSplit, Substring, Upper}
24+
import org.apache.spark.sql.catalyst.expressions.{Attribute, Cast, Concat, ConcatWs, Expression, If, InitCap, IsNull, Left, Length, Like, Literal, Lower, RegExpReplace, Right, RLike, StringLPad, StringRepeat, StringRPad, StringSplit, Substring, Upper}
2525
import org.apache.spark.sql.types.{BinaryType, DataTypes, LongType, StringType}
2626
import org.apache.spark.unsafe.types.UTF8String
2727

@@ -199,6 +199,27 @@ object CometConcat extends CometScalarFunction[Concat]("concat") {
199199
}
200200
}
201201

202+
object CometConcatWs extends CometExpressionSerde[ConcatWs] {
203+
204+
override def convert(expr: ConcatWs, inputs: Seq[Attribute], binding: Boolean): Option[Expr] = {
205+
expr.children.headOption match {
206+
// Match Spark behavior: when the separator is NULL, the result of concat_ws is NULL.
207+
case Some(Literal(null, _)) =>
208+
val nullLiteral = Literal.create(null, expr.dataType)
209+
exprToProtoInternal(nullLiteral, inputs, binding)
210+
211+
case _ if expr.children.forall(_.foldable) =>
212+
// Fall back to Spark for all-literal args so ConstantFolding can handle it
213+
withInfo(expr, "all arguments are foldable")
214+
None
215+
216+
case _ =>
217+
// For all other cases, use the generic scalar function implementation.
218+
CometScalarFunction[ConcatWs]("concat_ws").convert(expr, inputs, binding)
219+
}
220+
}
221+
}
222+
202223
object CometLike extends CometExpressionSerde[Like] {
203224

204225
override def convert(expr: Like, inputs: Seq[Attribute], binding: Boolean): Option[Expr] = {

spark/src/test/resources/sql-tests/expressions/string/concat_ws.sql

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,6 @@ INSERT INTO names VALUES(1, 'James', 'B', 'Taylor'), (2, 'Smith', 'C', 'Davis'),
4242
query
4343
SELECT concat_ws(' ', first_name, middle_initial, last_name) FROM names
4444

45-
-- literal + literal + literal
46-
query ignore(https://github.com/apache/datafusion-comet/issues/3339)
45+
-- literal + literal + literal (falls back to Spark when all args are foldable)
46+
query spark_answer_only
4747
SELECT concat_ws(',', 'hello', 'world'), concat_ws(',', '', ''), concat_ws(',', NULL, 'b', 'c'), concat_ws(NULL, 'a', 'b')

0 commit comments

Comments
 (0)