github-actions[bot] commented on code in PR #68934:
URL: https://github.com/apache/doris/pull/68934#discussion_r4245058048


##########
fe/fe-connector/fe-connector-paimon/src/main/java/org/apache/doris/connector/paimon/PaimonScanPlanProvider.java:
##########
@@ -964,7 +968,7 @@ && hasTrustworthyLimitAccounting(table)
             Optional<List<RawFile>> optRawFiles = 
dataSplit.convertToRawFiles();
             Optional<List<DeletionFile>> optDeletionFiles = 
dataSplit.deletionFiles();
 
-            boolean nativeEligible = 
shouldUseNativeReader(paimonHandle.isForceJni(),
+            boolean nativeEligible = 
shouldUseNativeReader(paimonHandle.isForceJni() || needsNanosecondReader,

Review Comment:
   [P2] Preserve metadata columns when routing nanosecond scans. A normal 
Paimon table advertises `__paimon_file_path` and `__paimon_row_index`, but 
selecting either with a `TIMESTAMP(7-9)` field sets `needsNanosecondReader` and 
makes `nativeEligible` false here. The JNI branch then calls 
`validateMetadataColumnReader(true, false)` and rejects every raw-convertible 
split, whereas its FileScannerV2 native path previously served the query. This 
needs a reader path that preserves both nanoseconds and physical metadata, plus 
a regression query covering the combination.



##########
be/src/format_v2/orc/orc_reader.cpp:
##########
@@ -947,6 +953,12 @@ Status OrcReader::init(RuntimeState* state) {
     try {
         _state->reader = ::orc::createReader(std::move(input_stream), options);
         _state->root_type = &_state->reader->getType();
+        if (orc_serde_utils::has_nanosecond_timestamp(*_state->root_type)) {
+            // Use the same UTC wall-clock carrier as the writer; historical 
local offsets
+            // differ between ORC and cctz and can push boundary values out of 
range.
+            _state->timezone = "GMT";

Review Comment:
   [P1] Keep the ORC negative-fraction correction when changing reader 
timezone. For an external Iceberg ORC stripe written with `Asia/Shanghai`, a 
valid `timestamp_ns` wall time `1970-01-01 00:00:00.500000000` enters ORC 1.9.0 
as second `-28800`; its writer stores `-28799` for the fractional-second 
encoding. This new file-wide GMT reader mode shifts that to `+1`, so ORC's 
reader skips its correction (which runs only for negative adjusted seconds), 
and Doris returns `00:00:01.500000000`. A plain timestamp in the same file 
follows the same path. Keep a compatible writer-zone conversion or correct the 
boundary before materialization, and cover a non-GMT external stripe crossing 
zero.



##########
fe/fe-connector/fe-connector-iceberg/src/main/java/org/apache/doris/connector/iceberg/IcebergPartitionUtils.java:
##########
@@ -479,6 +491,13 @@ static Object parsePartitionValueFromString(String 
valueStr, Type icebergType, Z
                 case DATE:
                     // Iceberg date is days since epoch (1970-01-01).
                     return (int) LocalDate.parse(valueStr, 
DateTimeFormatter.ISO_LOCAL_DATE).toEpochDay();
+                case TIMESTAMP_NANO:
+                    LocalDateTime timestampNs = 
LocalDateTime.parse(valueStr.replace('T', ' '),

Review Comment:
   [P2] Accept the write-side date-only form for static timestamp_ns 
partitions. `INSERT OVERWRITE ... PARTITION(ts='2024-01-01')` can materialize a 
valid midnight `TIMESTAMP_NS` row because its BE cast accepts the ten-character 
date, but the static partition map retains the raw string and this new 
`TIMESTAMP_NANO` parser requires `HH:mm:ss`. `buildPartitionFilter` then fails 
during overwrite commit, after writing files. Normalize the static value to the 
typed timestamp or parse the accepted date-only form here, and cover it with a 
static identity overwrite test.



##########
be/src/format/transformer/vorc_transformer.cpp:
##########
@@ -349,6 +355,11 @@ std::unique_ptr<orc::Type> 
VOrcTransformer::_build_orc_type(
         type = orc::createPrimitiveType(orc::DATE);
         break;
     }
+    case TYPE_TIMESTAMP_NS: {
+        type = orc::createPrimitiveType(orc::TIMESTAMP);
+        type->setAttribute("iceberg.timestamp-unit", "NANOS");

Review Comment:
   [P2] Preserve ORC nanoseconds in TVF and LOAD reads. This writer marks the 
field `iceberg.timestamp-unit=NANOS`, but legacy 
`OrcReader::convert_to_doris_type` ignores the attribute and infers 
`DATETIMEV2(6)` for TVF schema fetch and LOAD source columns. With 
`enable_file_scanner_v2=false`, a TVF scan uses that reader's `nanoseconds / 
1000` conversion, returning `.123456789` as `.123456`; LOAD also uses the 
legacy reader even when V2 is requested. Handle the annotation in inference and 
decoding, or route both paths through a lossless reader, and test both round 
trips.



##########
fe/fe-connector/fe-connector-paimon/src/main/java/org/apache/doris/connector/paimon/PaimonTypeMapping.java:
##########
@@ -156,6 +156,10 @@ private static ConnectorType toDecimalType(DecimalType 
type) {
     private static ConnectorType toTimestampType(DataType dataType) {
         int scale = DEFAULT_TIMESTAMP_SCALE;
         if (dataType instanceof TimestampType) {
+            // Keep all source fractional digits instead of truncating 
high-precision wall-clock values.
+            if (((TimestampType) dataType).getPrecision() > 
MAX_TIMESTAMP_SCALE) {
+                return ConnectorType.of("TIMESTAMP_NS");

Review Comment:
   [P2] Preserve access to high-precision Paimon values outside the nanosecond 
range. This maps every existing Paimon `TimestampType(7-9)` to `TIMESTAMP_NS`, 
whose signed 64-bit epoch range is only about 1677-2262. A valid existing value 
such as `1000-01-01 00:00:00` previously mapped to `DATETIMEV2(6)`, but the JNI 
`appendTimestampNs` path now reaches `Math.multiplyExact` in 
`TypeNativeBytes.convertToTimestampNs` and aborts the scan. Please retain a 
compatibility route or make the narrower range opt-in for existing tables, and 
test an out-of-range historical row.



##########
be/src/exec/sink/writer/iceberg/viceberg_partition_writer.cpp:
##########
@@ -84,10 +109,14 @@ Status VIcebergPartitionWriter::open(RuntimeState* state, 
RuntimeProfile* profil
             open_status = parquet_compression_type.error();
             break;
         }
-        ParquetFileOptions parquet_options = {.compression_type = 
parquet_compression_type.value(),
-                                              .parquet_version = 
TParquetVersion::PARQUET_1_0,
-                                              .parquet_disable_dictionary = 
false,
-                                              .enable_int96_timestamps = 
false};
+        // Parquet 1.0 coerces Arrow nanoseconds to microseconds, including 
nested fields.
+        ParquetFileOptions parquet_options = {
+                .compression_type = parquet_compression_type.value(),
+                .parquet_version = 
contains_nanosecond_timestamp(_schema.root_struct())

Review Comment:
   [P2] Preserve Parquet nanoseconds in TVF and LOAD reads. This new Parquet 2 
write path emits unadjusted `TIMESTAMP(NANOS)`, but legacy 
`format/parquet/schema_desc.cpp` declares it `DATETIMEV2(6)`. TVF schema fetch 
fixes that type before forced FileScannerV2 decodes the physical 
`TIMESTAMP_NS`, so `ColumnMapper` rounds `.123456789` to `.123457`. LOAD 
disables V2 and its legacy `Int64ToTimestamp` converter keeps only 
microseconds. Update both schema inference and legacy load conversion (or route 
them through lossless decoding), and test both file round trips.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


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

Reply via email to