Skip to content
Snippets Groups Projects
Commit d8afd45f authored by lgieron's avatar lgieron Committed by Sean Owen
Browse files

[SPARK-13515] Make FormatNumber work irrespective of locale.

## What changes were proposed in this pull request?

Change in class FormatNumber to make it work irrespective of locale.

## How was this patch tested?

Unit tests.

Author: lgieron <lgieron@gmail.com>

Closes #11396 from lgieron/SPARK-13515_Fix_Format_Number.
parent 75e618de
No related branches found
No related tags found
No related merge requests found
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
package org.apache.spark.sql.catalyst.expressions package org.apache.spark.sql.catalyst.expressions
import java.text.DecimalFormat import java.text.{DecimalFormat, DecimalFormatSymbols}
import java.util.{HashMap, Locale, Map => JMap} import java.util.{HashMap, Locale, Map => JMap}
import org.apache.spark.sql.catalyst.InternalRow import org.apache.spark.sql.catalyst.InternalRow
...@@ -938,8 +938,10 @@ case class FormatNumber(x: Expression, d: Expression) ...@@ -938,8 +938,10 @@ case class FormatNumber(x: Expression, d: Expression)
@transient @transient
private val pattern: StringBuffer = new StringBuffer() private val pattern: StringBuffer = new StringBuffer()
// SPARK-13515: US Locale configures the DecimalFormat object to use a dot ('.')
// as a decimal separator.
@transient @transient
private val numberFormat: DecimalFormat = new DecimalFormat("") private val numberFormat = new DecimalFormat("", new DecimalFormatSymbols(Locale.US))
override protected def nullSafeEval(xObject: Any, dObject: Any): Any = { override protected def nullSafeEval(xObject: Any, dObject: Any): Any = {
val dValue = dObject.asInstanceOf[Int] val dValue = dObject.asInstanceOf[Int]
...@@ -962,10 +964,9 @@ case class FormatNumber(x: Expression, d: Expression) ...@@ -962,10 +964,9 @@ case class FormatNumber(x: Expression, d: Expression)
pattern.append("0") pattern.append("0")
} }
} }
val dFormat = new DecimalFormat(pattern.toString)
lastDValue = dValue lastDValue = dValue
numberFormat.applyPattern(dFormat.toPattern) numberFormat.applyLocalizedPattern(pattern.toString)
} }
x.dataType match { x.dataType match {
...@@ -992,6 +993,11 @@ case class FormatNumber(x: Expression, d: Expression) ...@@ -992,6 +993,11 @@ case class FormatNumber(x: Expression, d: Expression)
val sb = classOf[StringBuffer].getName val sb = classOf[StringBuffer].getName
val df = classOf[DecimalFormat].getName val df = classOf[DecimalFormat].getName
val dfs = classOf[DecimalFormatSymbols].getName
val l = classOf[Locale].getName
// SPARK-13515: US Locale configures the DecimalFormat object to use a dot ('.')
// as a decimal separator.
val usLocale = "US"
val lastDValue = ctx.freshName("lastDValue") val lastDValue = ctx.freshName("lastDValue")
val pattern = ctx.freshName("pattern") val pattern = ctx.freshName("pattern")
val numberFormat = ctx.freshName("numberFormat") val numberFormat = ctx.freshName("numberFormat")
...@@ -999,7 +1005,8 @@ case class FormatNumber(x: Expression, d: Expression) ...@@ -999,7 +1005,8 @@ case class FormatNumber(x: Expression, d: Expression)
val dFormat = ctx.freshName("dFormat") val dFormat = ctx.freshName("dFormat")
ctx.addMutableState("int", lastDValue, s"$lastDValue = -100;") ctx.addMutableState("int", lastDValue, s"$lastDValue = -100;")
ctx.addMutableState(sb, pattern, s"$pattern = new $sb();") ctx.addMutableState(sb, pattern, s"$pattern = new $sb();")
ctx.addMutableState(df, numberFormat, s"""$numberFormat = new $df("");""") ctx.addMutableState(df, numberFormat,
s"""$numberFormat = new $df("", new $dfs($l.$usLocale));""")
s""" s"""
if ($d >= 0) { if ($d >= 0) {
...@@ -1013,9 +1020,8 @@ case class FormatNumber(x: Expression, d: Expression) ...@@ -1013,9 +1020,8 @@ case class FormatNumber(x: Expression, d: Expression)
$pattern.append("0"); $pattern.append("0");
} }
} }
$df $dFormat = new $df($pattern.toString());
$lastDValue = $d; $lastDValue = $d;
$numberFormat.applyPattern($dFormat.toPattern()); $numberFormat.applyLocalizedPattern($pattern.toString());
} }
${ev.value} = UTF8String.fromString($numberFormat.format(${typeHelper(num)})); ${ev.value} = UTF8String.fromString($numberFormat.format(${typeHelper(num)}));
} else { } else {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment