piby180 opened a new issue, #18881:
URL: https://github.com/apache/pinot/issues/18881

   ### Summary
   
   After upgrading from 1.5.0 to a recent 1.6.0-SNAPSHOT, equality comparison 
between a `TIMESTAMP` column and an epoch-millis `LONG` literal silently 
returns **no rows** in the **multi-stage engine** when the literal has 
millisecond precision. This used to work in 1.5.0.
   
   ### Possible Root cause
   
   PR #18396  changed `PinotTypeCoercion.binaryComparisonCoercion()` so that 
for `tsColumn <op> bigintLiteral`, the cast is now placed on the **literal** 
side (`tsColumn <op> CAST(literal AS TIMESTAMP)`) instead of on the column side 
(`CAST(tsColumn AS BIGINT) <op> literal`), to keep the column unwrapped.
   
   The new cast is created without a precision:
   
   ```java
   // pinot-query-planner/.../validate/PinotTypeCoercion.java
   return coerceOperandType(binding.getScope(), binding.getCall(), intIdx,
       factory.createSqlType(SqlTypeName.TIMESTAMP));   // no precision -> 
Calcite default = 0
   ```
   
   Pinot's `TypeSystem.getDefaultPrecision()` only overrides `DECIMAL`, so 
`TIMESTAMP` falls through to Calcite's default precision of **0 (seconds, no
   fractional part)**. When the literal cast is constant-folded, the sub-second 
portion is truncated:
   
   ```
   1761667561482  ->  TIMESTAMP '2025-10-28 14:06:01'  ->  1761667561000
   ```
   
   Stored rows hold `...561482`; the folded literal is `...561000`, so the 
predicate never matches.
   
   This is consistent with the existing tests passing: `TypeCoercion.json` and 
`PinotTypeCoercionTest` only use **whole-second** literals (e.g. `TS_LITERAL_MS 
= 1746022135000L` = `2025-04-30 14:08:55.000`), so the precision-0 truncation 
is invisible. No test covers a sub-second epoch literal.
   
   ### Schema
   
   ```json
   {
     "name": "processing_time",
     "dataType": "TIMESTAMP",
     "format": "1:MILLISECONDS:EPOCH",
     "granularity": "1:MILLISECONDS"
   }
   ```
   
   ### Steps to reproduce (multi-stage engine)
   
   Assume a row exists where `processing_time = 1761667561482` (`2025-10-28 
14:06:01.482Z`).
   
   **Returns no rows (regression):**
   ```sql
   SELECT * FROM tbl WHERE processing_time = 1761667561482;
   SELECT * FROM tbl WHERE processing_time = 
fromTimestamp(fromISO8601('2025-10-28T14:06:01.482Z'));
   ```
   
   **Works (workarounds):**
   ```sql
   -- forces the old column->LONG path
   SELECT * FROM tbl WHERE CAST(processing_time AS LONG) = 1761667561482;
   
   -- normalizes both sides to the same granularity
   SELECT * FROM tbl
   WHERE datetrunc('millisecond', processing_time)
       = datetrunc('millisecond', 
fromTimestamp(fromISO8601('2025-10-28T16:06:01.482000Z')));
   ```
   
   ### Expected behavior
   
   `processing_time = 1761667561482` should match rows whose stored millis equal
   `1761667561482`, preserving millisecond precision — as it did in 1.5.0.
   
   ### Actual behavior
   
   The BIGINT literal is cast to a precision-0 `TIMESTAMP` and constant-folded, 
truncating sub-second milliseconds; the equality silently matches nothing.
   
   ### Suggested fix
   
   Preserve millisecond precision on the implicit cast. Either:
   
   1. In `PinotTypeCoercion`, build the cast type with precision 3:
      ```java
      factory.createSqlType(SqlTypeName.TIMESTAMP, 3)
      ```
      (apply to both the literal->TIMESTAMP coercion and, for symmetry, 
anywhere a
      TIMESTAMP type is synthesized for comparison/folding), **or**
   
   2. Override `TypeSystem.getDefaultPrecision(TIMESTAMP)` to return `3`, since
      Pinot's execution type for `TIMESTAMP` is millisecond-precision `LONG`.
   
   ### Environment
   
   - Affected: 1.6.0-SNAPSHOT (commit `dc4e957717`, and any build containing 
#18396 / `a915903593`)
   - Not affected: 1.5.0
   - Engine: multi-stage (single-stage engine is unaffected — it treats 
TIMESTAMP/LONG as interchangeable longs)
   
   cc @yashmayya 


-- 
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