@@ -21,7 +21,7 @@ package org.apache.comet.serde
2121
2222import 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 }
2525import org .apache .spark .sql .types .{BinaryType , DataTypes , LongType , StringType }
2626import 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+
202223object CometLike extends CometExpressionSerde [Like ] {
203224
204225 override def convert (expr : Like , inputs : Seq [Attribute ], binding : Boolean ): Option [Expr ] = {
0 commit comments