This is an automated email from the ASF dual-hosted git repository.

uros-b pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/spark.git


The following commit(s) were added to refs/heads/master by this push:
     new 409b37efc3ab [SPARK-59823][SQL] Deduplicate variant manipulation 
expressions
409b37efc3ab is described below

commit 409b37efc3abaf390a772f225d6442240892233e
Author: bojana-db <[email protected]>
AuthorDate: Tue Sep 29 20:20:44 2026 +0000

    [SPARK-59823][SQL] Deduplicate variant manipulation expressions
    
    ### What changes were proposed in this pull request?
    This PR consolidates parsed-path caching, value-type validation, and 
nullable code-generation handling shared by variant manipulation expressions.
    
    ### Why are the changes needed?
    The refactor removes duplicated implementations while preserving existing 
behavior and making the manipulation expressions easier to maintain.
    
    ### Does this PR introduce _any_ user-facing change?
    No
    
    ### How was this patch tested?
    `VariantExpressionSuite`: five focused manipulation-expression tests passed
    
    ### Was this patch authored or co-authored using generative AI tooling?
    Generated-by: Codex (Astra)
    
    Closes #59073 from bojana-db/refactor-variant-manipulation.
    
    Authored-by: bojana-db <[email protected]>
    Signed-off-by: Uros Bojanic <[email protected]>
---
 .../expressions/variant/variantExpressions.scala   | 340 +++++++--------------
 .../variant/VariantExpressionSuite.scala           |   2 +-
 2 files changed, 118 insertions(+), 224 deletions(-)

diff --git 
a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/variant/variantExpressions.scala
 
b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/variant/variantExpressions.scala
index 0affceb09f1e..da0c45a981c8 100644
--- 
a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/variant/variantExpressions.scala
+++ 
b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/variant/variantExpressions.scala
@@ -391,6 +391,89 @@ object VariantPathParser extends RegexParsers {
   }
 }
 
+sealed trait VariantPathArg
+
+case class FoldableVariantPath(segments: Array[VariantPathSegment], pathStr: 
String)
+    extends VariantPathArg {
+  // Retain the original path for insert/set/append error messages. 
`VariantBuilder.PathSegment`
+  // is not `Serializable`, so the Java form is `@transient` and re-derived 
once per executor task
+  // after deserialization.
+  @transient lazy val javaSegments: Array[VariantBuilder.PathSegment] =
+    VariantExpressionEvalUtils.toJavaSegments(segments)
+}
+
+case class DynamicVariantPath(expr: Expression) extends VariantPathArg
+
+object VariantPathArg {
+  private def parseFoldableExpression(
+      child: Expression,
+      functionName: String,
+      allowRoot: Boolean): Option[FoldableVariantPath] = {
+    val value = child.eval()
+    if (value == null) {
+      None
+    } else {
+      val pathStr = value.asInstanceOf[UTF8String].toString
+      Some(FoldableVariantPath(
+        VariantExpressionEvalUtils.parseVariantPath(pathStr, functionName, 
allowRoot), pathStr))
+    }
+  }
+
+  def fromExpression(
+      child: Expression,
+      functionName: String,
+      allowRoot: Boolean = false): Option[VariantPathArg] = {
+    if (child.foldable) {
+      parseFoldableExpression(child, functionName, allowRoot)
+    } else {
+      Some(DynamicVariantPath(child))
+    }
+  }
+
+  def foldableFromExpression(
+      child: Expression,
+      functionName: String,
+      allowRoot: Boolean = false): Option[FoldableVariantPath] = {
+    if (child.foldable) {
+      parseFoldableExpression(child, functionName, allowRoot)
+    } else {
+      None
+    }
+  }
+}
+
+object VariantManipulationExpressionUtils extends QueryErrorsBase {
+  // Callers cache this result and force parsing before their NULL 
short-circuit.
+  // A dynamic path or constant NULL has no cached parsed path.
+  def foldablePath(
+      path: Expression,
+      functionName: String,
+      allowRoot: Boolean = false): Option[FoldableVariantPath] =
+    VariantPathArg.foldableFromExpression(path, functionName, allowRoot)
+
+  def checkValueType(dataType: DataType): TypeCheckResult = {
+    if (dataType == NullType || VariantGet.checkDataType(dataType, 
allowStructsAndMaps = false)) {
+      TypeCheckResult.TypeCheckSuccess
+    } else {
+      DataTypeMismatch(
+        errorSubClass = "CAST_WITHOUT_SUGGESTION",
+        messageParameters =
+          Map("srcType" -> toSQLType(dataType), "targetType" -> 
toSQLType(VariantType)))
+    }
+  }
+
+  def assignVariantResult(ev: ExprCode, call: String, nullable: Boolean): 
String = {
+    if (nullable) {
+      s"""
+         |${ev.value} = $call;
+         |${ev.isNull} = ${ev.value} == null;
+       """.stripMargin
+    } else {
+      s"${ev.value} = $call;"
+    }
+  }
+}
+
 /**
  * The implementation for `variant_get` and `try_variant_get` expressions. 
Extracts a sub-variant
  * value according to a path and cast it into a concrete data type.
@@ -912,8 +995,8 @@ case class VariantDelete(children: Seq[Expression])
   private def variantChild: Expression = children.head
   private def pathChildren: Seq[Expression] = children.tail
 
-  @transient private lazy val pathArgs: Seq[VariantDelete.DeletePathArg] =
-    pathChildren.flatMap(VariantDelete.toPathArg)
+  @transient private lazy val pathArgs: Seq[VariantPathArg] =
+    pathChildren.flatMap(VariantPathArg.fromExpression(_, prettyName))
 
   override def eval(input: InternalRow): Any = {
     val inputVariant = variantChild.eval(input).asInstanceOf[VariantVal]
@@ -923,9 +1006,9 @@ case class VariantDelete(children: Seq[Expression])
     var i = 0
     while (i < args.length) {
       args(i) match {
-        case parsed: VariantDelete.ParsedDeletePath =>
+        case parsed: FoldableVariantPath =>
           current = VariantExpressionEvalUtils.deleteAtPath(current, 
parsed.javaSegments)
-        case VariantDelete.DynamicDeletePath(expr) =>
+        case DynamicVariantPath(expr) =>
           val pathVal = expr.eval(input).asInstanceOf[UTF8String]
           if (pathVal != null) {
             current = VariantExpressionEvalUtils.deleteAtPath(current, pathVal)
@@ -943,10 +1026,10 @@ case class VariantDelete(children: Seq[Expression])
     val current = ctx.freshName("vdCurrent")
 
     val perPath = pathArgs.map {
-      case parsed: VariantDelete.ParsedDeletePath =>
+      case parsed: FoldableVariantPath =>
         val parsedArg = ctx.addReferenceObj("vdParsed", parsed)
         s"$current = $cls.deleteAtPath($current, $parsedArg.javaSegments());"
-      case VariantDelete.DynamicDeletePath(expr) =>
+      case DynamicVariantPath(expr) =>
         val pCode = expr.genCode(ctx)
         s"""
            |${pCode.code}
@@ -975,31 +1058,6 @@ case class VariantDelete(children: Seq[Expression])
       newChildren: IndexedSeq[Expression]): VariantDelete = copy(children = 
newChildren)
 }
 
-object VariantDelete {
-  sealed trait DeletePathArg
-  case class ParsedDeletePath(segments: Array[VariantPathSegment]) extends 
DeletePathArg {
-    // `VariantBuilder.PathSegment` is not `Serializable`, so the cached Java 
form is
-    // `@transient` and re-initialized once per executor task after 
deserialization.
-    @transient lazy val javaSegments: Array[VariantBuilder.PathSegment] =
-      VariantExpressionEvalUtils.toJavaSegments(segments)
-  }
-  case class DynamicDeletePath(expr: Expression) extends DeletePathArg
-
-  private[variant] def toPathArg(child: Expression): Option[DeletePathArg] = {
-    if (child.foldable) {
-      val v = child.eval()
-      if (v == null) {
-        None
-      } else {
-        Some(ParsedDeletePath(VariantExpressionEvalUtils.parseVariantPath(
-          v.asInstanceOf[UTF8String].toString, "variant_delete")))
-      }
-    } else {
-      Some(DynamicDeletePath(child))
-    }
-  }
-}
-
 // scalastyle:off line.size.limit
 @ExpressionDescription(
   usage = "_FUNC_(v, path1[, path2, ...]) - Keeps only the fields or array 
elements of a variant " +
@@ -1060,16 +1118,16 @@ case class VariantPick(children: Seq[Expression])
   private def variantChild: Expression = children.head
   private def pathChildren: Seq[Expression] = children.tail
 
-  @transient private lazy val pathArgs: Seq[VariantPick.PickPathArg] =
-    pathChildren.flatMap(VariantPick.toPathArg)
+  @transient private lazy val pathArgs: Seq[VariantPathArg] =
+    pathChildren.flatMap(VariantPathArg.fromExpression(_, prettyName, 
allowRoot = true))
 
   // When every path is constant, the keep-tree is the same for all rows, so 
build it once here and
   // reuse it rather than rebuilding it per row. `None` means at least one 
path is dynamic.
   @transient private lazy val foldableTree: Option[VariantBuilder.PickNode] = {
-    if (pathArgs.forall(_.isInstanceOf[VariantPick.ParsedPickPath])) {
+    if (pathArgs.forall(_.isInstanceOf[FoldableVariantPath])) {
       val paths = new 
java.util.ArrayList[Array[VariantBuilder.PathSegment]](pathArgs.length)
       pathArgs.foreach {
-        case parsed: VariantPick.ParsedPickPath => 
paths.add(parsed.javaSegments)
+        case parsed: FoldableVariantPath => paths.add(parsed.javaSegments)
         case _ =>
       }
       Some(VariantBuilder.buildPickTree(paths))
@@ -1085,9 +1143,9 @@ case class VariantPick(children: Seq[Expression])
     var i = 0
     while (i < pathArgs.length) {
       pathArgs(i) match {
-        case parsed: VariantPick.ParsedPickPath =>
+        case parsed: FoldableVariantPath =>
           paths.add(parsed.javaSegments)
-        case VariantPick.DynamicPickPath(expr) =>
+        case DynamicVariantPath(expr) =>
           val pathVal = expr.eval(input).asInstanceOf[UTF8String]
           if (pathVal != null) {
             paths.add(VariantExpressionEvalUtils.parsePickPath(pathVal))
@@ -1125,10 +1183,10 @@ case class VariantPick(children: Seq[Expression])
         // At least one dynamic path: gather the paths per row, then project.
         val paths = ctx.freshName("vpPaths")
         val addPaths = pathArgs.map {
-          case parsed: VariantPick.ParsedPickPath =>
+          case parsed: FoldableVariantPath =>
             val parsedArg = ctx.addReferenceObj("vpParsed", parsed)
             s"$paths.add($parsedArg.javaSegments());"
-          case VariantPick.DynamicPickPath(expr) =>
+          case DynamicVariantPath(expr) =>
             val pCode = expr.genCode(ctx)
             s"""
                |${pCode.code}
@@ -1161,39 +1219,13 @@ case class VariantPick(children: Seq[Expression])
       newChildren: IndexedSeq[Expression]): VariantPick = copy(children = 
newChildren)
 }
 
-object VariantPick {
-  sealed trait PickPathArg
-  case class ParsedPickPath(segments: Array[VariantPathSegment]) extends 
PickPathArg {
-    // `VariantBuilder.PathSegment` is not `Serializable`, so the cached Java 
form is
-    // `@transient` and re-initialized once per executor task after 
deserialization.
-    @transient lazy val javaSegments: Array[VariantBuilder.PathSegment] =
-      VariantExpressionEvalUtils.toJavaSegments(segments)
-  }
-  case class DynamicPickPath(expr: Expression) extends PickPathArg
-
-  private[variant] def toPathArg(child: Expression): Option[PickPathArg] = {
-    if (child.foldable) {
-      val v = child.eval()
-      if (v == null) {
-        None
-      } else {
-        Some(ParsedPickPath(VariantExpressionEvalUtils.parseVariantPath(
-          v.asInstanceOf[UTF8String].toString, "variant_pick", allowRoot = 
true)))
-      }
-    } else {
-      Some(DynamicPickPath(child))
-    }
-  }
-}
-
 case class VariantInsert(
     input: Expression,
     path: Expression,
     value: Expression,
     failOnError: Boolean = true)
     extends TernaryExpression
-    with ExpectsInputTypes
-    with QueryErrorsBase {
+    with ExpectsInputTypes {
 
   override def first: Expression = input
   override def second: Expression = path
@@ -1210,36 +1242,13 @@ case class VariantInsert(
     val result = super.checkInputDataTypes()
     if (result.isFailure) {
       result
-    } else if (value.dataType == NullType) {
-      TypeCheckResult.TypeCheckSuccess
-    } else if (!VariantGet.checkDataType(value.dataType, allowStructsAndMaps = 
false)) {
-      DataTypeMismatch(
-        errorSubClass = "CAST_WITHOUT_SUGGESTION",
-        messageParameters =
-          Map("srcType" -> toSQLType(value.dataType), "targetType" -> 
toSQLType(VariantType)))
     } else {
-      TypeCheckResult.TypeCheckSuccess
+      VariantManipulationExpressionUtils.checkValueType(value.dataType)
     }
   }
 
-  // When the path is a foldable expression, parse it once at planning time 
and cache it. The Java
-  // segments are derived once per task (see `ParsedInsertPath`), avoiding a 
per-row conversion.
-  // `None` means the path is dynamic (or a foldable NULL, which makes the 
whole expression NULL and
-  // is never evaluated).
-  @transient private lazy val foldablePath: 
Option[VariantInsert.ParsedInsertPath] = {
-    if (path.foldable) {
-      val p = path.eval()
-      if (p == null) {
-        None
-      } else {
-        val s = p.asInstanceOf[UTF8String].toString
-        Some(VariantInsert.ParsedInsertPath(
-          VariantExpressionEvalUtils.parseVariantPath(s, prettyName), s))
-      }
-    } else {
-      None
-    }
-  }
+  @transient private lazy val foldablePath: Option[FoldableVariantPath] =
+    VariantManipulationExpressionUtils.foldablePath(path, prettyName)
 
   override def eval(input: InternalRow): Any = {
     val _ = foldablePath
@@ -1272,22 +1281,9 @@ case class VariantInsert(
       case None =>
         s"""$cls.insertAtPath($vVal, $pVal, $valVal, $fromArg, "$prettyName", 
$failOnError)"""
     }
-    if (failOnError) {
-      nullSafeCodeGen(ctx, ev,
-        (vVal, pVal, valVal) => s"${ev.value} = ${call(vVal, pVal, valVal)};")
-    } else {
-      val resultType = CodeGenerator.javaType(VariantType)
-      val tmp = ctx.freshName("insertResult")
-      nullSafeCodeGen(ctx, ev, (vVal, pVal, valVal) =>
-        s"""
-           |$resultType $tmp = ${call(vVal, pVal, valVal)};
-           |if ($tmp == null) {
-           |  ${ev.isNull} = true;
-           |} else {
-           |  ${ev.value} = $tmp;
-           |}
-         """.stripMargin)
-    }
+    nullSafeCodeGen(ctx, ev, (vVal, pVal, valVal) =>
+      VariantManipulationExpressionUtils.assignVariantResult(
+        ev, call(vVal, pVal, valVal), nullable))
   }
 
   override def prettyName: String = if (failOnError) "variant_insert" else 
"try_variant_insert"
@@ -1297,16 +1293,6 @@ case class VariantInsert(
     copy(input = newFirst, path = newSecond, value = newThird)
 }
 
-object VariantInsert {
-  // Caches a foldable path. `VariantBuilder.PathSegment` is not 
`Serializable`, so the Java form is
-  // `@transient` and re-derived once per executor task after deserialization. 
`pathStr` is the
-  // source string, retained for error messages.
-  case class ParsedInsertPath(segments: Array[VariantPathSegment], pathStr: 
String) {
-    @transient lazy val javaSegments: Array[VariantBuilder.PathSegment] =
-      VariantExpressionEvalUtils.toJavaSegments(segments)
-  }
-}
-
 abstract class VariantInsertExpressionBuilderBase(failOnError: Boolean) 
extends ExpressionBuilder {
   override def build(funcName: String, expressions: Seq[Expression]): 
Expression = {
     val numArgs = expressions.length
@@ -1431,36 +1417,13 @@ case class VariantSet(
           "inputName" -> toSQLId("create_if_missing"),
           "inputType" -> toSQLType(createIfMissing.dataType),
           "inputExpr" -> toSQLExpr(createIfMissing)))
-    } else if (value.dataType == NullType) {
-      TypeCheckResult.TypeCheckSuccess
-    } else if (!VariantGet.checkDataType(value.dataType, allowStructsAndMaps = 
false)) {
-      DataTypeMismatch(
-        errorSubClass = "CAST_WITHOUT_SUGGESTION",
-        messageParameters =
-          Map("srcType" -> toSQLType(value.dataType), "targetType" -> 
toSQLType(VariantType)))
     } else {
-      TypeCheckResult.TypeCheckSuccess
+      VariantManipulationExpressionUtils.checkValueType(value.dataType)
     }
   }
 
-  // When the path is a foldable expression, parse it once at planning time 
and cache it. The Java
-  // segments are derived once per task (see `ParsedSetPath`), avoiding a 
per-row conversion. `None`
-  // means the path is dynamic (or a foldable NULL, which makes the whole 
expression NULL and is
-  // never evaluated).
-  @transient private lazy val foldablePath: Option[VariantSet.ParsedSetPath] = 
{
-    if (path.foldable) {
-      val p = path.eval()
-      if (p == null) {
-        None
-      } else {
-        val s = p.asInstanceOf[UTF8String].toString
-        Some(VariantSet.ParsedSetPath(
-          VariantExpressionEvalUtils.parseVariantPath(s, prettyName), s))
-      }
-    } else {
-      None
-    }
-  }
+  @transient private lazy val foldablePath: Option[FoldableVariantPath] =
+    VariantManipulationExpressionUtils.foldablePath(path, prettyName)
 
   override def eval(input: InternalRow): Any = {
     val _ = foldablePath
@@ -1496,23 +1459,10 @@ case class VariantSet(
           s"""$cls.setAtPath(
              |  $vVal, $pVal, $valVal, $fromArg, $createVal, "$prettyName", 
$failOnError)"""
             .stripMargin
-      }
-    if (failOnError) {
-      nullSafeCodeGen(ctx, ev,
-        (vVal, pVal, valVal, createVal) => s"${ev.value} = ${call(vVal, pVal, 
valVal, createVal)};")
-    } else {
-      val resultType = CodeGenerator.javaType(VariantType)
-      val tmp = ctx.freshName("setResult")
-      nullSafeCodeGen(ctx, ev, (vVal, pVal, valVal, createVal) =>
-        s"""
-           |$resultType $tmp = ${call(vVal, pVal, valVal, createVal)};
-           |if ($tmp == null) {
-           |  ${ev.isNull} = true;
-           |} else {
-           |  ${ev.value} = $tmp;
-           |}
-         """.stripMargin)
     }
+    nullSafeCodeGen(ctx, ev, (vVal, pVal, valVal, createVal) =>
+      VariantManipulationExpressionUtils.assignVariantResult(
+        ev, call(vVal, pVal, valVal, createVal), nullable))
   }
 
   override def prettyName: String = if (failOnError) "variant_set" else 
"try_variant_set"
@@ -1525,16 +1475,6 @@ case class VariantSet(
     copy(input = newFirst, path = newSecond, value = newThird, createIfMissing 
= newFourth)
 }
 
-object VariantSet {
-  // Caches a foldable path. `VariantBuilder.PathSegment` is not 
`Serializable`, so the Java form is
-  // `@transient` and re-derived once per executor task after deserialization. 
`pathStr` is the
-  // source string, retained for error messages.
-  case class ParsedSetPath(segments: Array[VariantPathSegment], pathStr: 
String) {
-    @transient lazy val javaSegments: Array[VariantBuilder.PathSegment] =
-      VariantExpressionEvalUtils.toJavaSegments(segments)
-  }
-}
-
 abstract class VariantSetExpressionBuilderBase(failOnError: Boolean) extends 
ExpressionBuilder {
   override def functionSignature: Option[FunctionSignature] = {
     val vArg = InputParameter("v")
@@ -1640,8 +1580,7 @@ case class VariantArrayAppend(
     value: Expression,
     failOnError: Boolean = true)
     extends TernaryExpression
-    with ExpectsInputTypes
-    with QueryErrorsBase {
+    with ExpectsInputTypes {
 
   override def first: Expression = input
   override def second: Expression = path
@@ -1658,35 +1597,13 @@ case class VariantArrayAppend(
     val result = super.checkInputDataTypes()
     if (result.isFailure) {
       result
-    } else if (value.dataType == NullType) {
-      TypeCheckResult.TypeCheckSuccess
-    } else if (!VariantGet.checkDataType(value.dataType, allowStructsAndMaps = 
false)) {
-      DataTypeMismatch(
-        errorSubClass = "CAST_WITHOUT_SUGGESTION",
-        messageParameters =
-          Map("srcType" -> toSQLType(value.dataType), "targetType" -> 
toSQLType(VariantType)))
     } else {
-      TypeCheckResult.TypeCheckSuccess
+      VariantManipulationExpressionUtils.checkValueType(value.dataType)
     }
   }
 
-  // When the path is a foldable expression, parse it once at planning time 
and cache it. `None`
-  // means the path is dynamic (or a foldable NULL, which makes the whole 
expression NULL
-  // and is never evaluated).
-  @transient private lazy val foldablePath: 
Option[VariantArrayAppend.ParsedAppendPath] = {
-    if (path.foldable) {
-      val p = path.eval()
-      if (p == null) {
-        None
-      } else {
-        val s = p.asInstanceOf[UTF8String].toString
-        Some(VariantArrayAppend.ParsedAppendPath(
-          VariantExpressionEvalUtils.parseVariantPath(s, prettyName, allowRoot 
= true), s))
-      }
-    } else {
-      None
-    }
-  }
+  @transient private lazy val foldablePath: Option[FoldableVariantPath] =
+    VariantManipulationExpressionUtils.foldablePath(path, prettyName, 
allowRoot = true)
 
   override def eval(input: InternalRow): Any = {
     val _ = foldablePath
@@ -1719,22 +1636,9 @@ case class VariantArrayAppend(
       case None =>
         s"""$cls.arrayAppendAtPath($vVal, $pVal, $valVal, $fromArg, 
"$prettyName", $failOnError)"""
     }
-    if (failOnError) {
-      nullSafeCodeGen(ctx, ev,
-        (vVal, pVal, valVal) => s"${ev.value} = ${call(vVal, pVal, valVal)};")
-    } else {
-      val resultType = CodeGenerator.javaType(VariantType)
-      val tmp = ctx.freshName("appendResult")
-      nullSafeCodeGen(ctx, ev, (vVal, pVal, valVal) =>
-        s"""
-           |$resultType $tmp = ${call(vVal, pVal, valVal)};
-           |if ($tmp == null) {
-           |  ${ev.isNull} = true;
-           |} else {
-           |  ${ev.value} = $tmp;
-           |}
-         """.stripMargin)
-    }
+    nullSafeCodeGen(ctx, ev, (vVal, pVal, valVal) =>
+      VariantManipulationExpressionUtils.assignVariantResult(
+        ev, call(vVal, pVal, valVal), nullable))
   }
 
   override def prettyName: String =
@@ -1745,16 +1649,6 @@ case class VariantArrayAppend(
     copy(input = newFirst, path = newSecond, value = newThird)
 }
 
-object VariantArrayAppend {
-  // Caches a foldable path. `VariantBuilder.PathSegment` is not 
`Serializable`, so the Java form is
-  // `@transient` and re-derived once per executor task after deserialization. 
`pathStr` is the
-  // source string, retained for error messages.
-  case class ParsedAppendPath(segments: Array[VariantPathSegment], pathStr: 
String) {
-    @transient lazy val javaSegments: Array[VariantBuilder.PathSegment] =
-      VariantExpressionEvalUtils.toJavaSegments(segments)
-  }
-}
-
 abstract class VariantArrayAppendExpressionBuilderBase(failOnError: Boolean)
     extends ExpressionBuilder {
   override def build(funcName: String, expressions: Seq[Expression]): 
Expression = {
diff --git 
a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/variant/VariantExpressionSuite.scala
 
b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/variant/VariantExpressionSuite.scala
index 75018a572b8b..634100197987 100644
--- 
a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/variant/VariantExpressionSuite.scala
+++ 
b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/variant/VariantExpressionSuite.scala
@@ -1459,7 +1459,7 @@ class VariantExpressionSuite extends SparkFunSuite with 
ExpressionEvalHelper {
     checkDelete("""{"a": null, "b": 2}""", Seq("$.a"), """{"b":2}""")
     checkDelete("[null, 1, null]", Seq("$[0]"), "[1,null]")
 
-    // Mixed literal + dynamic path exercises both `ParsedDeletePath` and 
`DynamicDeletePath`
+    // Mixed literal + dynamic path exercises both `FoldableVariantPath` and 
`DynamicVariantPath`
     // arms of `eval` in a single call.
     val mixedLitDyn = VariantDelete(Seq(
       Literal(parseJson("""{"a": 1, "b": 2, "c": 3}""")),


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to