Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion sql/core/src/main/scala/org/apache/spark/sql/functions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,17 @@ object functions {
* @group normal_funcs
* @since 1.3.0
*/
def lit(literal: Any): Column = typedLit(literal)
def lit(literal: Any): Column = literal match {
case c: Column => c
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you pass a column as a literal? if so, does it work this way currently?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep. I just inlined typedlit(literal) and changed Column(Literal.create(literal)) to Column(Literal(literal)). I don't expect there is any behavior difference.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh OK. That just seems odd that it's allowed? a literal that isn't a literal

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree it's odd. I don't know the context either 😄

case s: Symbol => new ColumnName(s.name)
case _ =>
// This is different from `typedlit`. `typedlit` calls `Literal.create` to use
// `ScalaReflection` to get the type of `literal`. However, since we use `Any` in this method,
// `typedLit[Any](literal)` will always fail and fallback to `Literal.apply`. Hence, we can
// just manually call `Literal.apply` to skip the expensive `ScalaReflection` code. This is
// significantly better when there are many threads calling `lit` concurrently.
Column(Literal(literal))
}

/**
* Creates a [[Column]] of literal value.
Expand All @@ -134,6 +144,9 @@ object functions {
* The difference between this function and [[lit]] is that this function
* can handle parameterized scala types e.g.: List, Seq and Map.
*
* @note `typedlit` will call expensive Scala reflection APIs. `lit` is preferred if parameterized
* Scala types are not used.
*
* @group normal_funcs
* @since 3.2.0
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -932,7 +932,19 @@ class ColumnExpressionSuite extends QueryTest with SharedSparkSession {
testData2.collect().toSeq.map(r => Row(r.getInt(0) ^ r.getInt(1) ^ 39)))
}

test("SPARK-37646: lit") {
assert(lit($"foo") == $"foo")
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't find any unit tests like this. So just add simple tests to cover 3 cases in the code.

assert(lit('foo) == $"foo")
assert(lit(1) == Column(Literal(1)))
assert(lit(null) == Column(Literal(null, NullType)))
}

test("typedLit") {
assert(typedLit($"foo") == $"foo")
assert(typedLit('foo) == $"foo")
assert(typedLit(1) == Column(Literal(1)))
assert(typedLit[String](null) == Column(Literal(null, StringType)))
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was trying to switch the order in Literal.create like this

  def create[T : TypeTag](v: T): Literal = 
 Try {
    Literal(v)
 }.getOrElse {
       Try {
          val ScalaReflection.Schema(dataType, _) = ScalaReflection.schemaFor[T]
          val convert = CatalystTypeConverters.createToCatalystConverter(dataType)
          Literal(convert(v), dataType)
        }.getOrElse {
          Literal(v)
        }
  }

and then realized this would break this use case. So just added this test to ensure we won't make such change in future.


val df = Seq(Tuple1(0)).toDF("a")
// Only check the types `lit` cannot handle
checkAnswer(
Expand Down