{"record":{"id":"dca488c3a313b066","repo":"risingwavelabs/risingwave","slug":"for-session-order-column-of-type-timestamptz-ga","errorCode":null,"errorMessage":"for session order column of type `timestamptz`, gap should not have non-zero `month` and `day`","messagePattern":"for session order column of type `timestamptz`, gap should not have non-zero `month` and `day`","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/expr/core/src/window_function/session.rs","lineNumber":113,"sourceCode":"\n        match self.gap.as_scalar_ref_impl() {\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 session gap 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 gap without `month` and `day` fields\n                    if val.months() != 0 || val.days() != 0 {\n                        bail!(\n                            \"for session order column of type `timestamptz`, gap 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\nimpl SessionFrameBounds {\n    pub fn minimal_next_start_of(&self, end_order_value: impl ToOwnedDatum) -> Datum {\n        self.gap.for_calc().minimal_next_start_of(end_order_value)\n    }\n}","sourceCodeStart":95,"sourceCodeEnd":131,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/expr/core/src/window_function/session.rs#L95-L131","documentation":"Session windows ordered by `timestamptz` only support gaps whose duration is expressible as exact microseconds — months and days have ambiguous, timezone/DST-dependent lengths. Therefore a gap for a timestamptz order column must have zero `months` and zero `days` fields.","triggerScenarios":"Session window whose order column is TIMESTAMPTZ and gap interval has non-zero months or days, e.g. `SESSION(INTERVAL '1 month')` over a timestamptz order key, caught in `validate` via `is_canonical`.","commonSituations":"Copy-pasting a session definition from a TIMESTAMP-column query to a TIMESTAMPTZ one; choosing '1 month'/'1 day' gaps intuitively without realizing the timestamptz restriction.","solutions":["Express the gap in hours/minutes/seconds/microseconds, e.g. INTERVAL '30 days' -> INTERVAL '720 hours'","Change the order column type to TIMESTAMP if day/month granularity is truly needed","Catch this at the frontend and emit a user-friendly hint"],"exampleFix":"// before\nOVER (ORDER BY ts_tz SESSION(INTERVAL '1 month'))\n// after\nOVER (ORDER BY ts_tz SESSION(INTERVAL '720 hours'))","handlingStrategy":"validation","validationCode":"fn timestamptz_safe_gap(i: Interval) -> bool { i.months() == 0 && i.days() == 0 }","typeGuard":null,"tryCatchPattern":"if order_type == DataType::Timestamptz && (gap.months() != 0 || gap.days() != 0) {\n    return Err(anyhow!(\"convert month/day gap to hours for timestamptz order columns\"));\n}","preventionTips":["Express timestamptz session gaps only in hours/minutes/seconds/microseconds","Use TIMESTAMP order columns if month/day gaps are required","Add a planner-level check with a helpful hint"],"tags":["rust","window-function","session-window","timestamptz"],"backgroundTag":"invalid-argument-value","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"}