@@ -22,6 +22,7 @@ package org.apache.comet.serde
2222import scala .annotation .tailrec
2323
2424import org .apache .spark .sql .catalyst .expressions .{ArrayAppend , ArrayContains , ArrayDistinct , ArrayExcept , ArrayFilter , ArrayInsert , ArrayIntersect , ArrayJoin , ArrayMax , ArrayMin , ArrayRemove , ArrayRepeat , ArraysOverlap , ArrayUnion , Attribute , CreateArray , ElementAt , Expression , Flatten , GetArrayItem , IsNotNull , Literal , Reverse , Size }
25+ import org .apache .spark .sql .catalyst .util .GenericArrayData
2526import org .apache .spark .sql .internal .SQLConf
2627import org .apache .spark .sql .types ._
2728
@@ -134,7 +135,34 @@ object CometArrayContains extends CometExpressionSerde[ArrayContains] {
134135
135136 val arrayContainsScalarExpr =
136137 scalarFunctionExprToProto(" array_has" , arrayExprProto, keyExprProto)
137- optExprWithInfo(arrayContainsScalarExpr, expr, expr.children: _* )
138+
139+ // Handle NULL array input - return NULL if array is NULL (matching Spark's behavior)
140+ val isNotNullExpr = createUnaryExpr(
141+ expr,
142+ expr.children.head,
143+ inputs,
144+ binding,
145+ (builder, unaryExpr) => builder.setIsNotNull(unaryExpr))
146+
147+ val nullLiteralProto = exprToProto(Literal (null , BooleanType ), Seq .empty)
148+
149+ if (arrayContainsScalarExpr.isDefined && isNotNullExpr.isDefined &&
150+ nullLiteralProto.isDefined) {
151+ val caseWhenExpr = ExprOuterClass .CaseWhen
152+ .newBuilder()
153+ .addWhen(isNotNullExpr.get)
154+ .addThen(arrayContainsScalarExpr.get)
155+ .setElseExpr(nullLiteralProto.get)
156+ .build()
157+ Some (
158+ ExprOuterClass .Expr
159+ .newBuilder()
160+ .setCaseWhen(caseWhenExpr)
161+ .build())
162+ } else {
163+ withInfo(expr, expr.children: _* )
164+ None
165+ }
138166 }
139167}
140168
@@ -395,6 +423,15 @@ object CometCreateArray extends CometExpressionSerde[CreateArray] {
395423 inputs : Seq [Attribute ],
396424 binding : Boolean ): Option [ExprOuterClass .Expr ] = {
397425 val children = expr.children
426+
427+ // Handle empty array: return literal directly to avoid DataFusion coerce_types bug
428+ // when make_array is called with 0 arguments (issue #3338)
429+ if (children.isEmpty) {
430+ val emptyArrayLiteral =
431+ Literal .create(new GenericArrayData (Array .empty[Any ]), expr.dataType)
432+ return exprToProtoInternal(emptyArrayLiteral, inputs, binding)
433+ }
434+
398435 val childExprs = children.map(exprToProtoInternal(_, inputs, binding))
399436
400437 if (childExprs.forall(_.isDefined)) {
0 commit comments