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

thisisnic pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow.git


The following commit(s) were added to refs/heads/main by this push:
     new d035788bd5 GH-48832: [R] Fix crash with zero-length POSIXct tzone 
attribute (#49619)
d035788bd5 is described below

commit d035788bd51e829cf55f3658dd0dd05fefc3080e
Author: Nic Crane <[email protected]>
AuthorDate: Thu Apr 2 13:42:27 2026 +0100

    GH-48832: [R] Fix crash with zero-length POSIXct tzone attribute (#49619)
    
    ### Rationale for this change
    
    In R 4.5.2+, `as.POSIXct(x = NULL)` creates a zero-length `POSIXct` with 
`INTSXP` (integer) type, not `REALSXP` (double). The `GetVectorType()` function 
in `r_to_arrow.cpp` only checked for `POSIXct` in the `REALSXP` branch, so it 
misclassified zero-length `POSIXct` as `INT32`.
    
    ### What changes are included in this PR?
    
    Map any `POSIXct` object to correct class by adding the check to the 
`INTSXP` branch of `GetVectorType()`
    
    ### Are these changes tested?
    
    Yes
    
    ### Are there any user-facing changes?
    
    No
    * GitHub Issue: #48832
    
    Authored-by: Nic Crane <[email protected]>
    Signed-off-by: Nic Crane <[email protected]>
---
 r/src/arrowExports.cpp          |  4 ++--
 r/src/r_to_arrow.cpp            |  2 ++
 r/tests/testthat/test-Array.R   | 11 +++++++++++
 r/tests/testthat/test-parquet.R | 10 ++++++++++
 4 files changed, 25 insertions(+), 2 deletions(-)

diff --git a/r/src/arrowExports.cpp b/r/src/arrowExports.cpp
index 5edf62d772..560466495e 100644
--- a/r/src/arrowExports.cpp
+++ b/r/src/arrowExports.cpp
@@ -5835,8 +5835,8 @@ static const R_CallMethodDef CallEntries[] = {
                { "_arrow_compute__GetFunctionNames", (DL_FUNC) 
&_arrow_compute__GetFunctionNames, 0}, 
                { "_arrow_compute__Initialize", (DL_FUNC) 
&_arrow_compute__Initialize, 0}, 
                { "_arrow_RegisterScalarUDF", (DL_FUNC) 
&_arrow_RegisterScalarUDF, 2}, 
-               { "_arrow_build_info", (DL_FUNC) &_arrow_build_info, 0},
-               { "_arrow_runtime_info", (DL_FUNC) &_arrow_runtime_info, 0},
+               { "_arrow_build_info", (DL_FUNC) &_arrow_build_info, 0}, 
+               { "_arrow_runtime_info", (DL_FUNC) &_arrow_runtime_info, 0}, 
                { "_arrow_csv___WriteOptions__initialize", (DL_FUNC) 
&_arrow_csv___WriteOptions__initialize, 1}, 
                { "_arrow_csv___ReadOptions__initialize", (DL_FUNC) 
&_arrow_csv___ReadOptions__initialize, 1}, 
                { "_arrow_csv___ParseOptions__initialize", (DL_FUNC) 
&_arrow_csv___ParseOptions__initialize, 1}, 
diff --git a/r/src/r_to_arrow.cpp b/r/src/r_to_arrow.cpp
index 4bee86ef68..45d68043af 100644
--- a/r/src/r_to_arrow.cpp
+++ b/r/src/r_to_arrow.cpp
@@ -93,6 +93,8 @@ RVectorType GetVectorType(SEXP x) {
         return FACTOR;
       } else if (Rf_inherits(x, "Date")) {
         return DATE_INT;
+      } else if (Rf_inherits(x, "POSIXct")) {
+        return POSIXCT;
       }
       return INT32;
     case STRSXP:
diff --git a/r/tests/testthat/test-Array.R b/r/tests/testthat/test-Array.R
index 03387f506f..8520160d12 100644
--- a/r/tests/testthat/test-Array.R
+++ b/r/tests/testthat/test-Array.R
@@ -324,6 +324,17 @@ test_that("array uses local timezone for POSIXct without 
timezone", {
   })
 })
 
+test_that("zero-length POSIXct can be converted (GH-48832)", {
+  # In R 4.5.2+, zero-length POSIXct vectors are integer type, not double
+  x <- as.POSIXct(x = NULL)
+
+  # Should behave the same as non-empty POSIXct with empty tzone
+  expect_type_equal(infer_type(x), timestamp("us"))
+  arr <- Array$create(x)
+  expect_equal(arr$length(), 0L)
+  expect_type_equal(arr, timestamp("us"))
+})
+
 test_that("Timezone handling in Arrow roundtrip (ARROW-3543)", {
   # Write a feather file as that's what the initial bug report used
   df <- tibble::tibble(
diff --git a/r/tests/testthat/test-parquet.R b/r/tests/testthat/test-parquet.R
index 47d73fb1e2..faa8d41e23 100644
--- a/r/tests/testthat/test-parquet.R
+++ b/r/tests/testthat/test-parquet.R
@@ -129,6 +129,16 @@ test_that("write_parquet() can truncate timestamps", {
   expect_equal(as.data.frame(tab), as.data.frame(new))
 })
 
+test_that("write_parquet() works with zero-length POSIXct (GH-48832)", {
+  # In R 4.5.2+, zero-length POSIXct vectors are integer type, not double
+  tf <- tempfile()
+  on.exit(unlink(tf))
+
+  expect_no_error(write_parquet(data.frame(x = as.POSIXct(x = NULL)), tf))
+  result <- read_parquet(tf)
+  expect_equal(nrow(result), 0)
+})
+
 test_that("make_valid_parquet_version()", {
   expect_equal(
     make_valid_parquet_version("1.0"),

Reply via email to