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

agrove pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/datafusion-comet.git


The following commit(s) were added to refs/heads/main by this push:
     new 1a560c61 fix: requested character too large for encoding in chr 
function (#552)
1a560c61 is described below

commit 1a560c615ff148b19cdec2eed3f01ad246a4aec6
Author: Vipul Vaibhaw <[email protected]>
AuthorDate: Fri Jun 14 20:47:37 2024 +0530

    fix: requested character too large for encoding in chr function (#552)
    
    * adding support for negative integers and modulo checks for int above 256, 
also added test case
    
    * fix test case to avoid cast integer overflow error
    
    * Update core/src/execution/datafusion/expressions/scalar_funcs/chr.rs
    
    Co-authored-by: Andy Grove <[email protected]>
    
    * returning negative ints as empty string earlier
    
    * adding scalar test and removing unreachable code
    
    * Update core/src/execution/datafusion/expressions/scalar_funcs/chr.rs
    
    Co-authored-by: Andy Grove <[email protected]>
    
    * Update spark/src/test/scala/org/apache/comet/CometExpressionSuite.scala
    
    Co-authored-by: Andy Grove <[email protected]>
    
    * add a test case where integer & 0xFF == 0
    
    ---------
    
    Co-authored-by: Andy Grove <[email protected]>
---
 .../datafusion/expressions/scalar_funcs/chr.rs     | 32 ++++++++++++++--------
 .../org/apache/comet/CometExpressionSuite.scala    | 24 ++++++++++++++++
 2 files changed, 44 insertions(+), 12 deletions(-)

diff --git a/core/src/execution/datafusion/expressions/scalar_funcs/chr.rs 
b/core/src/execution/datafusion/expressions/scalar_funcs/chr.rs
index 3d62d324..0421b491 100644
--- a/core/src/execution/datafusion/expressions/scalar_funcs/chr.rs
+++ b/core/src/execution/datafusion/expressions/scalar_funcs/chr.rs
@@ -44,10 +44,15 @@ pub fn chr(args: &[ArrayRef]) -> Result<ArrayRef> {
         .iter()
         .map(|integer: Option<i64>| {
             integer
-                .map(|integer| match core::char::from_u32(integer as u32) {
-                    Some(integer) => Ok(integer.to_string()),
-                    None => {
-                        exec_err!("requested character too large for 
encoding.")
+                .map(|integer| {
+                    if integer < 0 {
+                        return Ok("".to_string()); // Return empty string for 
negative integers
+                    }
+                    match core::char::from_u32((integer % 256) as u32) {
+                        Some(ch) => Ok(ch.to_string()),
+                        None => {
+                            exec_err!("requested character not compatible for 
encoding.")
+                        }
                     }
                 })
                 .transpose()
@@ -106,16 +111,19 @@ fn handle_chr_fn(args: &[ColumnarValue]) -> 
Result<ColumnarValue> {
             Ok(ColumnarValue::Array(array))
         }
         ColumnarValue::Scalar(ScalarValue::Int64(Some(value))) => {
-            match core::char::from_u32(value as u32) {
-                Some(ch) => Ok(ColumnarValue::Scalar(ScalarValue::Utf8(Some(
-                    ch.to_string(),
-                )))),
-                None => exec_err!("requested character too large for 
encoding."),
+            if value < 0 {
+                Ok(ColumnarValue::Scalar(ScalarValue::Utf8(Some(
+                    "".to_string(),
+                ))))
+            } else {
+                match core::char::from_u32((value % 256) as u32) {
+                    Some(ch) => 
Ok(ColumnarValue::Scalar(ScalarValue::Utf8(Some(
+                        ch.to_string(),
+                    )))),
+                    None => exec_err!("requested character was incompatible 
for encoding."),
+                }
             }
         }
-        ColumnarValue::Scalar(ScalarValue::Int64(None)) => {
-            Ok(ColumnarValue::Scalar(ScalarValue::Utf8(None)))
-        }
         _ => exec_err!("The argument must be an Int64 array or scalar."),
     }
 }
diff --git a/spark/src/test/scala/org/apache/comet/CometExpressionSuite.scala 
b/spark/src/test/scala/org/apache/comet/CometExpressionSuite.scala
index 2457f70a..ec45c984 100644
--- a/spark/src/test/scala/org/apache/comet/CometExpressionSuite.scala
+++ b/spark/src/test/scala/org/apache/comet/CometExpressionSuite.scala
@@ -1054,6 +1054,30 @@ class CometExpressionSuite extends CometTestBase with 
AdaptiveSparkPlanHelper {
     }
   }
 
+  test("Chr with negative and large value") {
+    Seq(false, true).foreach { dictionary =>
+      withSQLConf("parquet.enable.dictionary" -> dictionary.toString) {
+        val table = "test0"
+        withTable(table) {
+          sql(s"create table $table(c9 int, c4 int) using parquet")
+          sql(
+            s"insert into $table values(0, 0), (61231, -61231), (-1700, 1700), 
(0, -4000), (-40, 40), (256, 512)")
+          val query = s"SELECT chr(c9), chr(c4) FROM $table"
+          checkSparkAnswerAndOperator(query)
+        }
+      }
+    }
+
+    withParquetTable((0 until 5).map(i => (i % 5, i % 3)), "tbl") {
+      withSQLConf(
+        "spark.sql.optimizer.excludedRules" -> 
"org.apache.spark.sql.catalyst.optimizer.ConstantFolding") {
+        for (n <- Seq("0", "-0", "0.5", "-0.5", "555", "-555", "null")) {
+          checkSparkAnswerAndOperator(s"select chr(cast(${n} as int)) FROM 
tbl")
+        }
+      }
+    }
+  }
+
   test("InitCap") {
     Seq(false, true).foreach { dictionary =>
       withSQLConf("parquet.enable.dictionary" -> dictionary.toString) {


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

Reply via email to