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

jackietien pushed a commit to branch ExtractBug
in repository https://gitbox.apache.org/repos/asf/iotdb.git

commit a08b5d8eec4ff3e016e8314a295a840e8dfccb40
Author: JackieTien97 <[email protected]>
AuthorDate: Wed Aug 27 16:09:40 2025 +0800

    Fix DateTimeUtils init order bug
---
 .../plan/planner/plan/node/PlanGraphPrinter.java   |  7 +-
 .../scalar/DateBinFunctionColumnTransformer.java   | 21 +++---
 .../column/unary/scalar/ExtractTransformer.java    | 12 ++--
 .../java/org/apache/iotdb/db/service/DataNode.java |  4 ++
 .../org/apache/iotdb/db/utils/DateTimeUtils.java   | 75 ++++++++++++++--------
 5 files changed, 78 insertions(+), 41 deletions(-)

diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/PlanGraphPrinter.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/PlanGraphPrinter.java
index b07cc767910..a294448947f 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/PlanGraphPrinter.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/PlanGraphPrinter.java
@@ -20,6 +20,7 @@
 package org.apache.iotdb.db.queryengine.plan.planner.plan.node;
 
 import org.apache.iotdb.common.rpc.thrift.TRegionReplicaSet;
+import org.apache.iotdb.commons.conf.CommonDescriptor;
 import org.apache.iotdb.commons.partition.DataPartition;
 import org.apache.iotdb.commons.path.PartialPath;
 import org.apache.iotdb.db.queryengine.plan.analyze.TemplatedInfo;
@@ -99,7 +100,6 @@ import java.util.Map.Entry;
 import java.util.Optional;
 
 import static com.google.common.base.Preconditions.checkArgument;
-import static org.apache.iotdb.db.utils.DateTimeUtils.TIMESTAMP_PRECISION;
 
 public class PlanGraphPrinter extends PlanVisitor<List<String>, 
PlanGraphPrinter.GraphContext> {
 
@@ -837,7 +837,10 @@ public class PlanGraphPrinter extends 
PlanVisitor<List<String>, PlanGraphPrinter
     if (node.getMonthDuration() != 0) {
       boxValue.add(String.format("Interval: %smo", node.getMonthDuration()));
     } else {
-      boxValue.add(String.format("Interval: %s" + TIMESTAMP_PRECISION, 
node.getNonMonthDuration()));
+      boxValue.add(
+          String.format(
+              "Interval: %s" + 
CommonDescriptor.getInstance().getConfig().getTimestampPrecision(),
+              node.getNonMonthDuration()));
     }
     boxValue.add(String.format("GapFillColumn: %s", node.getGapFillColumn()));
     if (!node.getGapFillGroupingKeys().isEmpty()) {
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/transformation/dag/column/unary/scalar/DateBinFunctionColumnTransformer.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/transformation/dag/column/unary/scalar/DateBinFunctionColumnTransformer.java
index e0d51429ac6..93ef9dff3a2 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/transformation/dag/column/unary/scalar/DateBinFunctionColumnTransformer.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/transformation/dag/column/unary/scalar/DateBinFunctionColumnTransformer.java
@@ -19,6 +19,7 @@
 
 package org.apache.iotdb.db.queryengine.transformation.dag.column.unary.scalar;
 
+import org.apache.iotdb.commons.conf.CommonDescriptor;
 import 
org.apache.iotdb.db.queryengine.transformation.dag.column.ColumnTransformer;
 import 
org.apache.iotdb.db.queryengine.transformation.dag.column.unary.UnaryColumnTransformer;
 
@@ -32,8 +33,6 @@ import java.time.ZoneId;
 import java.time.temporal.ChronoUnit;
 import java.util.concurrent.TimeUnit;
 
-import static org.apache.iotdb.db.utils.DateTimeUtils.TIMESTAMP_PRECISION;
-
 public class DateBinFunctionColumnTransformer extends UnaryColumnTransformer {
 
   private static final long NANOSECONDS_IN_MILLISECOND = 1_000_000;
@@ -62,7 +61,7 @@ public class DateBinFunctionColumnTransformer extends 
UnaryColumnTransformer {
   private static LocalDateTime convertToLocalDateTime(long timestamp, ZoneId 
zoneId) {
     Instant instant;
 
-    switch (TIMESTAMP_PRECISION) {
+    switch 
(CommonDescriptor.getInstance().getConfig().getTimestampPrecision()) {
       case "ms":
         instant = Instant.ofEpochMilli(timestamp);
         break;
@@ -77,7 +76,9 @@ public class DateBinFunctionColumnTransformer extends 
UnaryColumnTransformer {
                 TimeUnit.NANOSECONDS.toSeconds(timestamp), timestamp % 
1_000_000_000);
         break;
       default:
-        throw new IllegalArgumentException("Unsupported precision: " + 
TIMESTAMP_PRECISION);
+        throw new IllegalArgumentException(
+            "Unsupported precision: "
+                + 
CommonDescriptor.getInstance().getConfig().getTimestampPrecision());
     }
 
     return LocalDateTime.ofInstant(instant, zoneId);
@@ -89,7 +90,7 @@ public class DateBinFunctionColumnTransformer extends 
UnaryColumnTransformer {
     // Get the nanoseconds section
     long nanoAdjustment = dateTime.getNano();
 
-    switch (TIMESTAMP_PRECISION) {
+    switch 
(CommonDescriptor.getInstance().getConfig().getTimestampPrecision()) {
       case "ms":
         return epochMilliSecond + nanoAdjustment / NANOSECONDS_IN_MILLISECOND;
       case "us":
@@ -98,12 +99,14 @@ public class DateBinFunctionColumnTransformer extends 
UnaryColumnTransformer {
       case "ns":
         return TimeUnit.MILLISECONDS.toNanos(epochMilliSecond) + 
nanoAdjustment;
       default:
-        throw new IllegalArgumentException("Unknown precision: " + 
TIMESTAMP_PRECISION);
+        throw new IllegalArgumentException(
+            "Unknown precision: "
+                + 
CommonDescriptor.getInstance().getConfig().getTimestampPrecision());
     }
   }
 
   private static long getNanoTimeStamp(long timestamp) {
-    switch (TIMESTAMP_PRECISION) {
+    switch 
(CommonDescriptor.getInstance().getConfig().getTimestampPrecision()) {
       case "ms":
         return TimeUnit.MILLISECONDS.toNanos(timestamp);
       case "us":
@@ -111,7 +114,9 @@ public class DateBinFunctionColumnTransformer extends 
UnaryColumnTransformer {
       case "ns":
         return timestamp;
       default:
-        throw new IllegalArgumentException("Unknown precision: " + 
TIMESTAMP_PRECISION);
+        throw new IllegalArgumentException(
+            "Unknown precision: "
+                + 
CommonDescriptor.getInstance().getConfig().getTimestampPrecision());
     }
   }
 
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/transformation/dag/column/unary/scalar/ExtractTransformer.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/transformation/dag/column/unary/scalar/ExtractTransformer.java
index 76d4c1c7e10..c8e11806f89 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/transformation/dag/column/unary/scalar/ExtractTransformer.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/transformation/dag/column/unary/scalar/ExtractTransformer.java
@@ -31,10 +31,10 @@ import java.time.ZoneId;
 import java.util.function.Function;
 
 import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_YEAR;
-import static 
org.apache.iotdb.db.utils.DateTimeUtils.EXTRACT_TIMESTAMP_MS_PART;
-import static 
org.apache.iotdb.db.utils.DateTimeUtils.EXTRACT_TIMESTAMP_NS_PART;
-import static 
org.apache.iotdb.db.utils.DateTimeUtils.EXTRACT_TIMESTAMP_US_PART;
 import static org.apache.iotdb.db.utils.DateTimeUtils.convertToZonedDateTime;
+import static 
org.apache.iotdb.db.utils.DateTimeUtils.getExtractTimestampMsPartFunction;
+import static 
org.apache.iotdb.db.utils.DateTimeUtils.getExtractTimestampNsPartFunction;
+import static 
org.apache.iotdb.db.utils.DateTimeUtils.getExtractTimestampUsPartFunction;
 
 public class ExtractTransformer extends UnaryColumnTransformer {
   private final Function<Long, Long> evaluateFunction;
@@ -72,11 +72,11 @@ public class ExtractTransformer extends 
UnaryColumnTransformer {
       case SECOND:
         return timestamp -> (long) convertToZonedDateTime(timestamp, 
zoneId).getSecond();
       case MS:
-        return EXTRACT_TIMESTAMP_MS_PART;
+        return getExtractTimestampMsPartFunction();
       case US:
-        return EXTRACT_TIMESTAMP_US_PART;
+        return getExtractTimestampUsPartFunction();
       case NS:
-        return EXTRACT_TIMESTAMP_NS_PART;
+        return getExtractTimestampNsPartFunction();
       default:
         throw new UnsupportedOperationException("Unexpected extract field: " + 
field);
     }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/service/DataNode.java 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/service/DataNode.java
index 55268d72ab2..bad4d839eac 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/service/DataNode.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/service/DataNode.java
@@ -137,6 +137,7 @@ import java.util.stream.Collectors;
 import static org.apache.iotdb.commons.conf.IoTDBConstant.DEFAULT_CLUSTER_NAME;
 import static 
org.apache.iotdb.commons.utils.StatusUtils.retrieveExitStatusCode;
 import static org.apache.iotdb.db.conf.IoTDBStartCheck.PROPERTIES_FILE_NAME;
+import static org.apache.iotdb.db.utils.DateTimeUtils.initTimestampPrecision;
 
 public class DataNode extends ServerCommandLine implements DataNodeMBean {
 
@@ -392,6 +393,9 @@ public class DataNode extends ServerCommandLine implements 
DataNodeMBean {
     } catch (Exception e) {
       throw new StartupException(e.getMessage());
     }
+
+    // init
+    initTimestampPrecision();
     long endTime = System.currentTimeMillis();
     logger.info(
         "Successfully pull system configurations from ConfigNode-leader, which 
takes {} ms",
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/DateTimeUtils.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/DateTimeUtils.java
index b413ae5ff37..63e577407cb 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/DateTimeUtils.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/DateTimeUtils.java
@@ -59,12 +59,11 @@ public class DateTimeUtils {
     // forbidding instantiation
   }
 
-  public static final String TIMESTAMP_PRECISION =
-      CommonDescriptor.getInstance().getConfig().getTimestampPrecision();
+  private static String timestampPrecision;
 
   public static long correctPrecision(long millis) {
     try {
-      switch (TIMESTAMP_PRECISION) {
+      switch (timestampPrecision) {
         case "us":
         case "microsecond":
           return Math.multiplyExact(millis, 1_000L);
@@ -80,44 +79,70 @@ public class DateTimeUtils {
       throw new IoTDBRuntimeException(
           String.format(
               "Timestamp overflow, Millisecond: %s , Timestamp precision: %s",
-              millis, TIMESTAMP_PRECISION),
+              millis, timestampPrecision),
           NUMERIC_VALUE_OUT_OF_RANGE.getStatusCode(),
           true);
     }
   }
 
-  public static final Function<Long, Long> CAST_TIMESTAMP_TO_MS;
-  public static final Function<Long, Long> EXTRACT_TIMESTAMP_MS_PART;
-  public static final Function<Long, Long> EXTRACT_TIMESTAMP_US_PART;
-  public static final Function<Long, Long> EXTRACT_TIMESTAMP_NS_PART;
+  private static Function<Long, Long> castTimestampToMs;
+  private static Function<Long, Long> extractTimestampMsPart;
+  private static Function<Long, Long> extractTimestampUsPart;
+  private static Function<Long, Long> extractTimestampNsPart;
 
-  static {
-    switch 
(CommonDescriptor.getInstance().getConfig().getTimestampPrecision()) {
+  private static void updateFunction() {
+    switch (timestampPrecision) {
       case "us":
       case "microsecond":
-        CAST_TIMESTAMP_TO_MS = timestamp -> timestamp / 1000;
-        EXTRACT_TIMESTAMP_MS_PART = timestamp -> Math.floorMod(timestamp, 
1000_000L) / 1000;
-        EXTRACT_TIMESTAMP_US_PART = timestamp -> Math.floorMod(timestamp, 
1000L);
-        EXTRACT_TIMESTAMP_NS_PART = timestamp -> 0L;
+        castTimestampToMs = timestamp -> timestamp / 1000;
+        extractTimestampMsPart = timestamp -> Math.floorMod(timestamp, 
1000_000L) / 1000;
+        extractTimestampUsPart = timestamp -> Math.floorMod(timestamp, 1000L);
+        extractTimestampNsPart = timestamp -> 0L;
         break;
       case "ns":
       case "nanosecond":
-        CAST_TIMESTAMP_TO_MS = timestamp -> timestamp / 1000000;
-        EXTRACT_TIMESTAMP_MS_PART = timestamp -> Math.floorMod(timestamp, 
1000_000_000L) / 1000_000;
-        EXTRACT_TIMESTAMP_US_PART = timestamp -> Math.floorMod(timestamp, 
1000_000L) / 1000;
-        EXTRACT_TIMESTAMP_NS_PART = timestamp -> Math.floorMod(timestamp, 
1000L);
+        castTimestampToMs = timestamp -> timestamp / 1000000;
+        extractTimestampMsPart = timestamp -> Math.floorMod(timestamp, 
1000_000_000L) / 1000_000;
+        extractTimestampUsPart = timestamp -> Math.floorMod(timestamp, 
1000_000L) / 1000;
+        extractTimestampNsPart = timestamp -> Math.floorMod(timestamp, 1000L);
         break;
       case "ms":
       case "millisecond":
       default:
-        CAST_TIMESTAMP_TO_MS = timestamp -> timestamp;
-        EXTRACT_TIMESTAMP_MS_PART = timestamp -> Math.floorMod(timestamp, 
1000L);
-        EXTRACT_TIMESTAMP_US_PART = timestamp -> 0L;
-        EXTRACT_TIMESTAMP_NS_PART = timestamp -> 0L;
+        castTimestampToMs = timestamp -> timestamp;
+        extractTimestampMsPart = timestamp -> Math.floorMod(timestamp, 1000L);
+        extractTimestampUsPart = timestamp -> 0L;
+        extractTimestampNsPart = timestamp -> 0L;
         break;
     }
   }
 
+  public static Function<Long, Long> getExtractTimestampMsPartFunction() {
+    if (extractTimestampMsPart == null) {
+      throw new IllegalArgumentException("ExtractTimestampMsPart is null");
+    }
+    return extractTimestampMsPart;
+  }
+
+  public static Function<Long, Long> getExtractTimestampUsPartFunction() {
+    if (extractTimestampUsPart == null) {
+      throw new IllegalArgumentException("ExtractTimestampUsPart is null");
+    }
+    return extractTimestampUsPart;
+  }
+
+  public static Function<Long, Long> getExtractTimestampNsPartFunction() {
+    if (extractTimestampNsPart == null) {
+      throw new IllegalArgumentException("ExtractTimestampNsPart is null");
+    }
+    return extractTimestampNsPart;
+  }
+
+  public static void initTimestampPrecision() {
+    timestampPrecision = 
CommonDescriptor.getInstance().getConfig().getTimestampPrecision();
+    updateFunction();
+  }
+
   private static final DateTimeFormatter DATE_FORMATTER = 
DateTimeFormatter.ofPattern("yyyy-MM-dd");
   public static final DateTimeFormatter ISO_LOCAL_DATE_WIDTH_1_2;
 
@@ -787,12 +812,12 @@ public class DateTimeUtils {
   }
 
   public static LocalDate convertToLocalDate(long timestamp, ZoneId zoneId) {
-    timestamp = CAST_TIMESTAMP_TO_MS.apply(timestamp);
+    timestamp = castTimestampToMs.apply(timestamp);
     return Instant.ofEpochMilli(timestamp).atZone(zoneId).toLocalDate();
   }
 
   public static ZonedDateTime convertToZonedDateTime(long timestamp, ZoneId 
zoneId) {
-    timestamp = CAST_TIMESTAMP_TO_MS.apply(timestamp);
+    timestamp = castTimestampToMs.apply(timestamp);
     return ZonedDateTime.ofInstant(Instant.ofEpochMilli(timestamp), zoneId);
   }
 
@@ -924,7 +949,7 @@ public class DateTimeUtils {
     parser1.getInterpreter().setPredictionMode(PredictionMode.SLL);
     parser1.removeErrorListeners();
     parser1.addErrorListener(SqlParseError.INSTANCE);
-    return astVisitor.parseDateExpression(parser1.dateExpression(), 
TIMESTAMP_PRECISION);
+    return astVisitor.parseDateExpression(parser1.dateExpression(), 
timestampPrecision);
   }
 
   public static Integer parseDateExpressionToInt(String dateExpression) {

Reply via email to