From 2d234e613248ec25b47bf26f63402cc1408bf7da Mon Sep 17 00:00:00 2001
From: Gabriel Musat Mestre <gabriel.musatmestre@datadoghq.com>
Date: Thu, 20 Mar 2025 16:56:43 +0100
Subject: [PATCH] Add producer.rs workarounds

---
 .../substrait/src/logical_plan/producer.rs    | 74 +++++++++----------
 .../tests/cases/roundtrip_logical_plan.rs     |  2 +
 2 files changed, 35 insertions(+), 41 deletions(-)

diff --git a/datafusion/substrait/src/logical_plan/producer.rs b/datafusion/substrait/src/logical_plan/producer.rs
index e4df9703b20ca..95df6870a79b5 100644
--- a/datafusion/substrait/src/logical_plan/producer.rs
+++ b/datafusion/substrait/src/logical_plan/producer.rs
@@ -43,6 +43,7 @@ use crate::variation_const::{
     LARGE_CONTAINER_TYPE_VARIATION_REF, UNSIGNED_INTEGER_TYPE_VARIATION_REF,
     VIEW_CONTAINER_TYPE_VARIATION_REF,
 };
+use crate::variation_const::TIMESTAMP_NANO_TYPE_VARIATION_REF;
 use datafusion::arrow::array::{Array, GenericListArray, OffsetSizeTrait};
 use datafusion::arrow::temporal_conversions::NANOSECONDS;
 use datafusion::common::{
@@ -1825,31 +1826,16 @@ fn to_substrait_type(dt: &DataType, nullable: bool) -> Result<substrait::proto::
                 nullability,
             })),
         }),
-        DataType::Timestamp(unit, tz) => {
-            let precision = match unit {
-                TimeUnit::Second => 0,
-                TimeUnit::Millisecond => 3,
-                TimeUnit::Microsecond => 6,
-                TimeUnit::Nanosecond => 9,
-            };
-            let kind = match tz {
-                None => r#type::Kind::PrecisionTimestamp(r#type::PrecisionTimestamp {
-                    type_variation_reference: DEFAULT_TYPE_VARIATION_REF,
+        DataType::Timestamp(_unit, _) => {
+            // TODO: DataDog-specific workaround, don't commit upstream
+            #[allow(deprecated)]
+            let type_variation_reference = TIMESTAMP_NANO_TYPE_VARIATION_REF;
+            Ok(substrait::proto::Type {
+                kind: Some(r#type::Kind::Timestamp(r#type::Timestamp {
+                    type_variation_reference,
                     nullability,
-                    precision,
-                }),
-                Some(_) => {
-                    // If timezone is present, no matter what the actual tz value is, it indicates the
-                    // value of the timestamp is tied to UTC epoch. That's all that Substrait cares about.
-                    // As the timezone is lost, this conversion may be lossy for downstream use of the value.
-                    r#type::Kind::PrecisionTimestampTz(r#type::PrecisionTimestampTz {
-                        type_variation_reference: DEFAULT_TYPE_VARIATION_REF,
-                        nullability,
-                        precision,
-                    })
-                }
-            };
-            Ok(substrait::proto::Type { kind: Some(kind) })
+                })),
+            })
         }
         DataType::Date32 => Ok(substrait::proto::Type {
             kind: Some(r#type::Kind::Date(r#type::Date {
@@ -2004,6 +1990,8 @@ fn to_substrait_type(dt: &DataType, nullable: bool) -> Result<substrait::proto::
                 precision: *p as i32,
             })),
         }),
+        // TODO: DataDog-specific workaround, don't commit upstream
+        DataType::Dictionary(_, dt) => to_substrait_type(dt, nullable),
         _ => not_impl_err!("Unsupported cast type: {dt:?}"),
     }
 }
@@ -2396,6 +2384,8 @@ fn to_substrait_literal(
             }),
             DEFAULT_TYPE_VARIATION_REF,
         ),
+        // TODO: DataDog-specific workaround, don't commit upstream
+        ScalarValue::Dictionary(_, value) => return to_substrait_literal(producer, value),
         _ => (
             not_impl_err!("Unsupported literal: {value:?}")?,
             DEFAULT_TYPE_VARIATION_REF,
@@ -2598,17 +2588,18 @@ mod test {
         round_trip_literal(ScalarValue::UInt64(Some(u64::MIN)))?;
         round_trip_literal(ScalarValue::UInt64(Some(u64::MAX)))?;
 
-        for (ts, tz) in [
-            (Some(12345), None),
-            (None, None),
-            (Some(12345), Some("UTC".into())),
-            (None, Some("UTC".into())),
-        ] {
-            round_trip_literal(ScalarValue::TimestampSecond(ts, tz.clone()))?;
-            round_trip_literal(ScalarValue::TimestampMillisecond(ts, tz.clone()))?;
-            round_trip_literal(ScalarValue::TimestampMicrosecond(ts, tz.clone()))?;
-            round_trip_literal(ScalarValue::TimestampNanosecond(ts, tz))?;
-        }
+        // TODO: DataDog-specific workaround, don't commit upstream
+        // for (ts, tz) in [
+        //     (Some(12345), None),
+        //     (None, None),
+        //     (Some(12345), Some("UTC".into())),
+        //     (None, Some("UTC".into())),
+        // ] {
+        //     round_trip_literal(ScalarValue::TimestampSecond(ts, tz.clone()))?;
+        //     round_trip_literal(ScalarValue::TimestampMillisecond(ts, tz.clone()))?;
+        //     round_trip_literal(ScalarValue::TimestampMicrosecond(ts, tz.clone()))?;
+        //     round_trip_literal(ScalarValue::TimestampNanosecond(ts, tz))?;
+        // }
 
         round_trip_literal(ScalarValue::List(ScalarValue::new_list_nullable(
             &[ScalarValue::Float32(Some(1.0))],
@@ -2707,12 +2698,13 @@ mod test {
         round_trip_type(DataType::Float32)?;
         round_trip_type(DataType::Float64)?;
 
-        for tz in [None, Some("UTC".into())] {
-            round_trip_type(DataType::Timestamp(TimeUnit::Second, tz.clone()))?;
-            round_trip_type(DataType::Timestamp(TimeUnit::Millisecond, tz.clone()))?;
-            round_trip_type(DataType::Timestamp(TimeUnit::Microsecond, tz.clone()))?;
-            round_trip_type(DataType::Timestamp(TimeUnit::Nanosecond, tz))?;
-        }
+        // TODO: DataDog-specific workaround, don't commit upstream
+        // for tz in [None, Some("UTC".into())] {
+        //     round_trip_type(DataType::Timestamp(TimeUnit::Second, tz.clone()))?;
+        //     round_trip_type(DataType::Timestamp(TimeUnit::Millisecond, tz.clone()))?;
+        //     round_trip_type(DataType::Timestamp(TimeUnit::Microsecond, tz.clone()))?;
+        //     round_trip_type(DataType::Timestamp(TimeUnit::Nanosecond, tz))?;
+        // }
 
         round_trip_type(DataType::Date32)?;
         round_trip_type(DataType::Date64)?;
diff --git a/datafusion/substrait/tests/cases/roundtrip_logical_plan.rs b/datafusion/substrait/tests/cases/roundtrip_logical_plan.rs
index e6b8bdbc047e3..14c75929a61f1 100644
--- a/datafusion/substrait/tests/cases/roundtrip_logical_plan.rs
+++ b/datafusion/substrait/tests/cases/roundtrip_logical_plan.rs
@@ -950,6 +950,7 @@ async fn qualified_catalog_schema_table_reference() -> Result<()> {
 /// - List, this nested type is not supported in arrow_cast
 /// - Decimal128 and Decimal256, them will fallback to UTF8 cast expr rather than plain literal.
 #[tokio::test]
+#[ignore] // TODO: DataDog-specific workaround, don't commit upstream
 async fn all_type_literal() -> Result<()> {
     roundtrip_all_types(
         "select * from data where
@@ -1073,6 +1074,7 @@ async fn duplicate_column() -> Result<()> {
 
 /// Construct a plan that cast columns. Only those SQL types are supported for now.
 #[tokio::test]
+#[ignore] // TODO: DataDog-specific workaround, don't commit upstream
 async fn new_test_grammar() -> Result<()> {
     roundtrip_all_types(
         "select
