cockroachdb / cockroachdb/cockroach

sql/opt: NormalizeCmpTimeZoneFunction silently masks "exceeds supported timestamp bounds" errors

Open
#169,202 1 comment 0 reactions 0 assignees View on GitHub
A-sql-optimizer C-bug O-agent S-3-erroneous-edge-case T-sql-queries
Dominant language
Go
Stars
32.5k
Forks
4.1k
PR merge metrics
PR metrics pending

Description

**Describe the problem**

The `NormalizeCmpTimeZoneFunction` (and its `NormalizeCmpTimeZoneFunctionTZ`
sibling) normalization rule rewrites a predicate of the form
`timezone(zone, ts) op const` into `ts op (timezone-shifted const)`,
hoisting the per-row `timezone(...)` call out so the comparison can use a
constant on the right-hand side. When the per-row evaluation of
`timezone(zone, ts)` would push the value past the supported `TIMESTAMP`
bound (`294276-12-31 23:59:59.999999`), the rewrite silently suppresses the
bounds error and returns a result that the original expression could not
have produced.

This is the same class of bug as #125751 — predicate rewrites that ignore
runtime evaluation errors — but for a different rule and a different error
class (timestamp bounds vs. float precision). #125751 does not mention this
rule.

**To Reproduce**

Setup:

```sql
CREATE TABLE t (ts TIMESTAMP);
INSERT INTO t VALUES ('294276-12-31 23:59:59.999999'); -- upper TIMESTAMP bound
```

With the rule disabled, per-row evaluation errors as expected:

```sql
SET disable_optimizer_rules = 'NormalizeCmpTimeZoneFunction';
SELECT timezone('America/Denver', ts) >= '2020-06-01 12:35:55-07' FROM t;
```

```
ERROR: timestamp "294277-01-01T06:59:59Z" exceeds supported timestamp bounds
```

With the rule enabled (default), the query silently succeeds:

```sql
SET disable_optimizer_rules = '';
SELECT timezone('America/Denver', ts) >= '2020-06-01 12:35:55-07' FROM t;
```

```
?column?
------------
true
(1 row)
```

`EXPLAIN (OPT)` confirms the rewrite:
- Rule enabled: `ts >= '2020-06-01 13:35:55'` (no `timezone(...)` call).
- Rule disabled: `timezone('America/Denver', ts) >= '2020-06-01 12:35:55-07'`.

**Expected behavior**

If a per-row evaluation of `timezone(zone, ts)` would error with
\"timestamp exceeds supported timestamp bounds\", the query should error
regardless of whether the optimizer chooses to rewrite the predicate. The
rewrite is only valid when the two plans agree on success-and-error
behavior across all input rows.

**Actual behavior**

With the rule enabled (the default), the rewritten plan never evaluates
`timezone(zone, ts)` per row, so the bounds check is bypassed and the
query returns `true` for the boundary row.

**Additional context**

How it was found: a per-rule differential testing harness for the
optimizer's normalization rules. For each query in the rules' hand-written
testdata, run with the rule enabled and again with
`SET disable_optimizer_rules = ''`. Any divergence in the result
set is a candidate correctness bug. Random boundary-aware data populated
by `randgen.PopulateTableWithRandData` (which inserts upper-bound
`TIMESTAMP` values) caused the bounds-error case to surface for this
rule in the `pkg/sql/opt/norm/testdata/rules/comp` corpus.

A self-contained regression check, as a logictest stanza appended to
`pkg/sql/logictest/testdata/logic_test/timestamp` — fails on master,
will pass once the rule is patched:

```text
subtest regression_normalize_cmp_timezone_bounds

statement ok
CREATE TABLE timezone_bounds_t (ts TIMESTAMP)

statement ok
INSERT INTO timezone_bounds_t VALUES ('294276-12-31 23:59:59.999999')

# Sanity check: with the rule disabled, per-row evaluation errors as
# expected on the boundary row.
statement ok
SET disable_optimizer_rules = 'NormalizeCmpTimeZoneFunction'

query error exceeds supported timestamp bounds
SELECT timezone('America/Denver', ts) >= '2020-06-01 12:35:55-07' FROM timezone_bounds_t

statement ok
SET disable_optimizer_rules = ''

# With the rule enabled (default), the rewrite must not silently mask
# the bounds error.
query error exceeds supported timestamp bounds
SELECT timezone('America/Denver', ts) >= '2020-06-01 12:35:55-07' FROM timezone_bounds_t

statement ok
DROP TABLE timezone_bounds_t

subtest end
```

Related: #125751 — `sql: optimizer folds away constants in arithmetic
equality comparisons` — same class of bug for `NormalizeCmpPlusConst` /
`NormalizeCmpConstMinus` and float precision rather than timestamp bounds.

Jira issue: CRDB-63328

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.