Skip to content

Commit d5bbbf7

Browse files
committed
[GLUTEN-11622][VL] Add basic TIMESTAMP_NTZ type support (#11939)
1 parent 9c34b45 commit d5bbbf7

29 files changed

Lines changed: 333 additions & 40 deletions

File tree

backends-velox/src-delta33/test/scala/org/apache/spark/sql/delta/DeltaInsertIntoTableSuite.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1423,7 +1423,8 @@ abstract class DeltaInsertIntoTests(
14231423
}
14241424
}
14251425

1426-
test("insertInto: Timestamp No Timezone round trips across timezones") {
1426+
// Cast from TIMESTAMP_NTZ to TIMESTAMP has not been supported.
1427+
ignore("insertInto: Timestamp No Timezone round trips across timezones") {
14271428
val t1 = "timestamp_ntz"
14281429
withTable(t1) {
14291430
withTimeZone("GMT-8") {

backends-velox/src/main/scala/org/apache/gluten/backendsapi/velox/VeloxValidatorApi.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,9 @@ object VeloxValidatorApi {
112112
YearMonthIntervalType.DEFAULT | NullType =>
113113
true
114114
case dt if !enableTimestampNtzValidation && dt.catalogString == "timestamp_ntz" => true
115+
// Allow TimestampNTZ when validation is disabled (for development/testing)
116+
// Use reflection to avoid compile-time dependency on Spark 3.4+ TimestampNTZType
117+
true
115118
case _ => false
116119
}
117120
}

backends-velox/src/main/scala/org/apache/gluten/config/VeloxConfig.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -827,5 +827,5 @@ object VeloxConfig extends ConfigRegistry {
827827
"containing TimestampNTZ will fall back to Spark execution. Set to false during " +
828828
"development/testing of TimestampNTZ support to allow native execution.")
829829
.booleanConf
830-
.createWithDefault(true)
830+
.createWithDefault(false)
831831
}

backends-velox/src/main/scala/org/apache/gluten/execution/VeloxColumnarToRowExec.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ case class VeloxColumnarToRowExec(child: SparkPlan) extends ColumnarToRowExecBas
5050
case _: DoubleType =>
5151
case _: StringType =>
5252
case _: TimestampType =>
53+
case other if other.typeName == "timestamp_ntz" =>
5354
case _: DateType =>
5455
case _: BinaryType =>
5556
case _: DecimalType =>

backends-velox/src/test/scala/org/apache/gluten/execution/FallbackSuite.scala

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@ class FallbackSuite extends VeloxWholeStageTransformerSuite with AdaptiveSparkPl
310310
}
311311
}
312312

313-
test("fallback with index based schema evolution") {
313+
testWithMinSparkVersion("fallback with index based schema evolution", "3.4") {
314314
val query = "SELECT c2 FROM test"
315315
Seq("parquet", "orc").foreach {
316316
format =>
@@ -333,9 +333,7 @@ class FallbackSuite extends VeloxWholeStageTransformerSuite with AdaptiveSparkPl
333333
runQueryAndCompare(query) {
334334
df =>
335335
val plan = df.queryExecution.executedPlan
336-
val fallback = parquetUseColumnNames == "false" ||
337-
orcUseColumnNames == "false"
338-
assert(collect(plan) { case g: GlutenPlan => g }.isEmpty == fallback)
336+
assert(collect(plan) { case g: GlutenPlan => g }.nonEmpty)
339337
}
340338
}
341339
}

backends-velox/src/test/scala/org/apache/gluten/execution/VeloxParquetDataTypeValidationSuite.scala

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import org.apache.gluten.backendsapi.velox.VeloxValidatorApi
2020
import org.apache.gluten.config.{GlutenConfig, VeloxConfig}
2121

2222
import org.apache.spark.SparkConf
23+
import org.apache.spark.sql.Row
2324

2425
import java.io.File
2526

@@ -466,17 +467,17 @@ class VeloxParquetDataTypeValidationSuite extends VeloxWholeStageTransformerSuit
466467
}
467468
}
468469

469-
testWithMinSparkVersion("Fallback for TimestampNTZ type scan", "3.4") {
470+
testWithMinSparkVersion("TimestampNTZ type scan", "3.4") {
470471
withTempDir {
471472
dir =>
472473
val path = new File(dir, "ntz_data").toURI.getPath
473474
val inputDf =
474475
spark.sql("SELECT CAST('2024-01-01 00:00:00' AS TIMESTAMP_NTZ) AS ts_ntz")
475476
inputDf.write.format("parquet").save(path)
476-
val df = spark.read.format("parquet").load(path)
477+
val df = spark.read.parquet(path)
477478
val executedPlan = getExecutedPlan(df)
478-
assert(!executedPlan.exists(plan => plan.isInstanceOf[BatchScanExecTransformer]))
479-
checkAnswer(df, inputDf)
479+
assert(executedPlan.exists(plan => plan.isInstanceOf[BatchScanExecTransformer]))
480+
checkAnswer(df, Seq(Row(java.time.LocalDateTime.of(2024, 1, 1, 0, 0, 0, 0))))
480481
}
481482
}
482483

backends-velox/src/test/scala/org/apache/gluten/functions/DateFunctionsValidateSuite.scala

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
*/
1717
package org.apache.gluten.functions
1818

19-
import org.apache.gluten.execution.ProjectExecTransformer
19+
import org.apache.gluten.execution.{BatchScanExecTransformer, ProjectExecTransformer}
2020

2121
import org.apache.spark.sql.execution.ProjectExec
2222
import org.apache.spark.sql.types.Decimal
@@ -569,4 +569,43 @@ class DateFunctionsValidateSuite extends FunctionsValidateSuite {
569569
}
570570
}
571571

572+
testWithMinSparkVersion("read as timestamp_ntz", "3.4") {
573+
val inputs: Seq[String] = Seq(
574+
"1970-01-01",
575+
"1970-01-01 00:00:00-02:00",
576+
"1970-01-01 00:00:00 +02:00",
577+
"2000-01-01",
578+
"1970-01-01 00:00:00",
579+
"2000-01-01 12:21:56",
580+
"2015-03-18T12:03:17Z",
581+
"2015-03-18 12:03:17",
582+
"2015-03-18T12:03:17",
583+
"2015-03-18 12:03:17.123",
584+
"2015-03-18T12:03:17.123",
585+
"2015-03-18T12:03:17.456",
586+
"2015-03-18 12:03:17.456"
587+
)
588+
589+
withTempPath {
590+
dir =>
591+
val path = dir.getAbsolutePath
592+
val inputDF = spark.createDataset(inputs).toDF("input")
593+
val df = inputDF.selectExpr("cast(input as timestamp_ntz) as ts")
594+
df.coalesce(1).write.mode("overwrite").parquet(path)
595+
val readDf = spark.read.parquet(path)
596+
readDf.createOrReplaceTempView("view")
597+
598+
runQueryAndCompare("select * from view") {
599+
checkGlutenPlan[BatchScanExecTransformer]
600+
}
601+
602+
// Ensures the fallback of unsupported function works.
603+
runQueryAndCompare("select hour(ts) from view") {
604+
df =>
605+
assert(collect(df.queryExecution.executedPlan) {
606+
case p if p.isInstanceOf[ProjectExec] => p
607+
}.nonEmpty)
608+
}
609+
}
610+
}
572611
}

cpp/velox/substrait/SubstraitParser.cc

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,8 @@
1717

1818
#include "SubstraitParser.h"
1919
#include "TypeUtils.h"
20-
#include "velox/common/base/Exceptions.h"
21-
2220
#include "VeloxSubstraitSignature.h"
21+
#include "velox/common/base/Exceptions.h"
2322

2423
namespace gluten {
2524

@@ -78,6 +77,8 @@ TypePtr SubstraitParser::parseType(const ::substrait::Type& substraitType, bool
7877
return DATE();
7978
case ::substrait::Type::KindCase::kTimestampTz:
8079
return TIMESTAMP();
80+
case ::substrait::Type::KindCase::kTimestamp:
81+
return TIMESTAMP_UTC();
8182
case ::substrait::Type::KindCase::kDecimal: {
8283
auto precision = substraitType.decimal().precision();
8384
auto scale = substraitType.decimal().scale();
@@ -356,6 +357,9 @@ int64_t SubstraitParser::getLiteralValue(const ::substrait::Expression::Literal&
356357
memcpy(&decimalValue, decimal.c_str(), 16);
357358
return static_cast<int64_t>(decimalValue);
358359
}
360+
if (literal.has_timestamp()) {
361+
return literal.timestamp();
362+
}
359363
return literal.i64();
360364
}
361365

cpp/velox/substrait/SubstraitToVeloxExpr.cc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,10 @@
1717

1818
#include "SubstraitToVeloxExpr.h"
1919
#include "TypeUtils.h"
20+
#include "velox/type/Timestamp.h"
2021
#include "velox/vector/FlatVector.h"
2122
#include "velox/vector/VariantToVector.h"
2223

23-
#include "velox/type/Timestamp.h"
24-
2524
using namespace facebook::velox;
2625

2726
namespace {
@@ -133,6 +132,8 @@ TypePtr getScalarType(const ::substrait::Expression::Literal& literal) {
133132
return DATE();
134133
case ::substrait::Expression_Literal::LiteralTypeCase::kTimestampTz:
135134
return TIMESTAMP();
135+
case ::substrait::Expression_Literal::LiteralTypeCase::kTimestamp:
136+
return TIMESTAMP_UTC();
136137
case ::substrait::Expression_Literal::LiteralTypeCase::kString:
137138
return VARCHAR();
138139
case ::substrait::Expression_Literal::LiteralTypeCase::kVarChar:

cpp/velox/substrait/SubstraitToVeloxPlan.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828

2929
#include "utils/ConfigExtractor.h"
3030
#include "utils/ObjectStore.h"
31+
#include "utils/VeloxArrowUtils.h"
3132
#include "utils/VeloxWriterUtils.h"
3233

3334
#include "config.pb.h"

0 commit comments

Comments
 (0)