{"record":{"id":"98ef84c64e91b489","repo":"risingwavelabs/risingwave","slug":"for-frame-order-column-of-type-timestamptz-offs","errorCode":null,"errorMessage":"for frame order column of type `timestamptz`, offset should not have non-zero `month` and `day`","messagePattern":"for frame order column of type `timestamptz`, offset should not have non-zero `month` and `day`","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/expr/core/src/window_function/range.rs","lineNumber":126,"sourceCode":"            match offset.as_scalar_ref_impl() {\n                // TODO(rc): use decl macro?\n                ScalarRefImpl::Int16(val) => validate_non_negative(val)?,\n                ScalarRefImpl::Int32(val) => validate_non_negative(val)?,\n                ScalarRefImpl::Int64(val) => validate_non_negative(val)?,\n                ScalarRefImpl::Float32(val) => validate_non_negative(val)?,\n                ScalarRefImpl::Float64(val) => validate_non_negative(val)?,\n                ScalarRefImpl::Decimal(val) => validate_non_negative(val)?,\n                ScalarRefImpl::Interval(val) => {\n                    if !val.is_never_negative() {\n                        bail!(\n                            \"for frame bound offset of type `interval`, each field should be non-negative, but {} is given\",\n                            val\n                        );\n                    }\n                    if matches!(self.order_data_type, DataType::Timestamptz) {\n                        // for `timestamptz`, we only support offset without `month` and `day` fields\n                        if val.months() != 0 || val.days() != 0 {\n                            bail!(\n                                \"for frame order column of type `timestamptz`, offset should not have non-zero `month` and `day`\",\n                            );\n                        }\n                    }\n                }\n                _ => unreachable!(\n                    \"other order column data types are not supported and should be banned in frontend\"\n                ),\n            }\n            Ok(())\n        })\n    }\n}\n\nimpl RangeFrameBounds {\n    /// Get the frame start for a given order column value.\n    ///\n    /// ## Examples","sourceCodeStart":108,"sourceCodeEnd":144,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/expr/core/src/window_function/range.rs#L108-L144","documentation":"When the RANGE frame order column is of type timestamptz, RisingWave only supports interval offsets that are pure microsecond durations; offsets with non-zero month or day fields cannot be added to a timestamptz in a timezone-independent way, so validate rejects them.","triggerScenarios":"RANGE frame over a timestamptz order column with an offset like `INTERVAL '1 month'` or `INTERVAL '1 day'` (months() or days() != 0).","commonSituations":"`OVER (ORDER BY ts RANGE BETWEEN INTERVAL '1 month' PRECEDING AND CURRENT ROW)` on a timestamptz column; DST/calendar ambiguity makes such offsets unsupported.","solutions":["Rewrite the offset in pure time units, e.g. `INTERVAL '30 days'` -> approximate with seconds (`INTERVAL '2592000 seconds'`) only if semantics allow, or better use a days-based column type.","Cast the order column to timestamp (without tz) if calendar semantics are acceptable and the type supports it.","Use ROWS frames with an explicit row count instead of RANGE with calendar intervals."],"exampleFix":"-- before\nSELECT sum(x) OVER (ORDER BY ts_at_tz RANGE BETWEEN INTERVAL '1 month' PRECEDING AND CURRENT ROW) FROM t;\n-- after\nSELECT sum(x) OVER (ORDER BY ts RANGE BETWEEN INTERVAL '30 days' PRECEDING AND CURRENT ROW) FROM t; -- order col must be non-timestamptz, or use seconds-based offset","handlingStrategy":"validation","validationCode":"fn offset_ok_for_timestamptz(order_type: &DataType, i: &Interval) -> bool {\n    order_type != &DataType::Timestamptz || (i.months() == 0 && i.days() == 0)\n}","typeGuard":"fn is_pure_duration(i: &Interval) -> bool { i.months() == 0 && i.days() == 0 }","tryCatchPattern":null,"preventionTips":["Prefer timestamp (not timestamptz) order columns for calendar-based RANGE frames.","Use second/microsecond-only interval offsets with timestamptz.","Fall back to ROWS frames when calendar offsets are needed."],"tags":["window-function","range-frame","timestamptz","interval"],"backgroundTag":"unsupported-operation","analyzedSha":"6469eb736d691e8e9b8a419a57edd6429ca77417","analyzedAt":"2026-09-11T21:06:21.487Z","contentChangedAt":"2026-09-11T21:06:21.487Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}