{"record":{"id":"ab5213d74a1b13fc","repo":"risingwavelabs/risingwave","slug":"both-leading-or-trailing","errorCode":null,"errorMessage":"BOTH, LEADING, or TRAILING","messagePattern":"BOTH, LEADING, or TRAILING","errorType":"validation","errorClass":"ParserError","httpStatus":null,"severity":"error","filePath":"src/sqlparser/src/parser.rs","lineNumber":1117,"sourceCode":"            trim_what = Some(Box::new(self.parse_expr()?));\n        }\n        self.expect_token(&Token::RParen)?;\n\n        Ok(Expr::Trim {\n            expr: Box::new(expr),\n            trim_where,\n            trim_what,\n        })\n    }\n\n    pub fn parse_trim_where(&mut self) -> ModalResult<TrimWhereField> {\n        dispatch! { peek(keyword);\n            Keyword::BOTH => keyword.value(TrimWhereField::Both),\n            Keyword::LEADING => keyword.value(TrimWhereField::Leading),\n            Keyword::TRAILING => keyword.value(TrimWhereField::Trailing),\n            _ => fail\n        }\n        .expect(\"BOTH, LEADING, or TRAILING\")\n        .parse_next(self)\n    }\n\n    /// Parses an array expression `[ex1, ex2, ..]`\n    pub fn parse_array_expr(&mut self) -> ModalResult<Expr> {\n        let mut expected_depth = None;\n        let exprs = self.parse_array_inner(0, &mut expected_depth)?;\n        Ok(Expr::Array(Array {\n            elem: exprs,\n            // Top-level array is named.\n            named: true,\n        }))\n    }\n\n    fn parse_array_inner(\n        &mut self,\n        depth: usize,\n        expected_depth: &mut Option<usize>,","sourceCodeStart":1099,"sourceCodeEnd":1135,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/sqlparser/src/parser.rs#L1099-L1135","documentation":"Raised by `parse_trim_where` when parsing a TRIM expression's positioning keyword. After `TRIM(` the parser expects exactly one of BOTH, LEADING, or TRAILING when a positional specifier is present; any other token fails the dispatch and `.expect` produces 'BOTH, LEADING, or TRAILING'. It signals an invalid or missing TRIM modifier keyword.","triggerScenarios":"Parsing `TRIM(<bad-keyword> 'x' FROM col)` where the token after TRIM( is not BOTH/LEADING/TRAILING but is not a valid field either, e.g. `TRIM(LEFT 'x' FROM col)` or `TRIM(BOTHH 'x' FROM col)`.","commonSituations":"Queries ported from databases with nonstandard TRIM syntax (e.g. LEFT/RIGHT in some engines); typos in manually written TRIM calls; code generators emitting positional trim keywords from another dialect.","solutions":["Use one of the supported keywords: BOTH, LEADING, or TRAILING, e.g. `TRIM(LEADING 'x' FROM col)`.","If no positional keyword is needed, write `TRIM(col)` or `TRIM('x' FROM col)`.","Map dialect-specific keywords (LEFT/RIGHT) to LEADING/TRAILING before running."],"exampleFix":"// before\nSELECT TRIM(LEFT '0' FROM code) FROM t;\n// after\nSELECT TRIM(LEADING '0' FROM code) FROM t;","handlingStrategy":"validation","validationCode":"const TRIM_WHERE = new Set(['BOTH','LEADING','TRAILING']);\nfunction validTrimWhere(kw) { return TRIM_WHERE.has(kw.toUpperCase()); }","typeGuard":"const isTrimWhere = (s) => typeof s === 'string' && ['BOTH','LEADING','TRAILING'].includes(s.toUpperCase());","tryCatchPattern":null,"preventionTips":["Normalize dialect keywords LEFT/RIGHT to LEADING/TRAILING before generating TRIM.","Omit the positional keyword when default BOTH behavior is intended.","Lint generated SQL against a keyword whitelist."],"tags":["sql","parser","trim","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-14T16:17:12.679Z"}