{"record":{"id":"26214308c68e08f2","repo":"risingwavelabs/risingwave","slug":"rows-range-or-groups","errorCode":null,"errorMessage":"ROWS, RANGE, or GROUPS","messagePattern":"ROWS, RANGE, or GROUPS","errorType":"validation","errorClass":"ParserError","httpStatus":null,"severity":"error","filePath":"src/sqlparser/src/parser.rs","lineNumber":914,"sourceCode":"        Ok(Expr::Function(Function {\n            scalar_as_agg,\n            name,\n            arg_list,\n            within_group,\n            filter,\n            over,\n        }))\n    }\n\n    pub fn parse_window_frame_units(&mut self) -> ModalResult<WindowFrameUnits> {\n        dispatch! { peek(keyword);\n            Keyword::ROWS => keyword.value(WindowFrameUnits::Rows),\n            Keyword::RANGE => keyword.value(WindowFrameUnits::Range),\n            Keyword::GROUPS => keyword.value(WindowFrameUnits::Groups),\n            Keyword::SESSION => keyword.value(WindowFrameUnits::Session),\n            _ => fail,\n        }\n        .expect(\"ROWS, RANGE, or GROUPS\")\n        .parse_next(self)\n    }\n\n    pub fn parse_window_frame(&mut self) -> ModalResult<WindowFrame> {\n        let units = self.parse_window_frame_units()?;\n        let bounds = if self.parse_keyword(Keyword::BETWEEN) {\n            // `BETWEEN <frame_start> AND <frame_end>`\n            let start = self.parse_window_frame_bound()?;\n            self.expect_keyword(Keyword::AND)?;\n            let end = Some(self.parse_window_frame_bound()?);\n            WindowFrameBounds::Bounds { start, end }\n        } else if self.parse_keywords(&[Keyword::WITH, Keyword::GAP]) {\n            // `WITH GAP <gap>`, only for session frames\n            WindowFrameBounds::Gap(Box::new(self.parse_expr()?))\n        } else {\n            // `<frame_start>`\n            WindowFrameBounds::Bounds {\n                start: self.parse_window_frame_bound()?,","sourceCodeStart":896,"sourceCodeEnd":932,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/sqlparser/src/parser.rs#L896-L932","documentation":"This error is raised by `parse_window_frame_units` when the parser cannot recognize the frame unit keyword of a window frame clause (OVER ... ROWS/RANGE/GROUPS/SESSION). The `dispatch!` combinator only accepts ROWS, RANGE, GROUPS or SESSION; anything else fails and `.expect(...)` converts that failure into a user-facing 'expected ROWS, RANGE, or GROUPS' message. It is a SQL syntax error reporting that a window frame unit keyword was required but not found.","triggerScenarios":"Parsing a query with a window frame whose unit token is misspelled, missing, or unsupported, e.g. `OVER (ROWS ...)` missing nothing but written as `OVER (ROW BETWEEN ...)` or `OVER (PARTITION BY x ORDER BY y BETWEEN ...)` where the unit keyword is absent before BETWEEN/UNBOUNDED.","commonSituations":"Hand-written SQL with typos in window frame clauses; SQL dialects where window frames use different keywords; generated SQL from ORMs or query builders that emit nonstandard frame syntax; porting queries from other engines with exotic frame specs.","solutions":["Fix the window frame unit keyword to one of ROWS, RANGE, GROUPS (or SESSION in this dialect), e.g. `OVER (ORDER BY x ROWS BETWEEN 1 PRECEDING AND CURRENT ROW)`.","Ensure the frame clause actually contains a unit keyword before BETWEEN or the bound expression.","If the query came from another database, rewrite its frame clause to the supported unit keywords."],"exampleFix":"// before\nSELECT sum(v) OVER (ORDER BY t ROW BETWEEN 1 PRECEDING AND CURRENT ROW) FROM t;\n// after\nSELECT sum(v) OVER (ORDER BY t ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) FROM t;","handlingStrategy":"validation","validationCode":"const FRAME_UNITS = new Set(['ROWS','RANGE','GROUPS','SESSION']);\nfunction validFrameUnit(unit) { return FRAME_UNITS.has(unit.toUpperCase()); }","typeGuard":"const isFrameUnit = (s) => typeof s === 'string' && ['ROWS','RANGE','GROUPS','SESSION'].includes(s.toUpperCase());","tryCatchPattern":null,"preventionTips":["Always write the unit keyword before BETWEEN/UNBOUNDED in a window frame clause.","Run SQL through the parser in CI before deploying generated queries.","Map dialect-specific frame keywords before executing."],"tags":["sql","parser","window-function","syntax"],"backgroundTag":"invalid-enum-value","analyzedSha":"6469eb736d691e8e9b8a419a57edd6429ca77417","analyzedAt":"2026-09-11T21:06:21.487Z","contentChangedAt":"2026-09-11T21:06:21.487Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}