{"record":{"id":"de5c9f6961859e3c","repo":"risingwavelabs/risingwave","slug":"date-time-field-de5c9f","errorCode":null,"errorMessage":"date/time field","messagePattern":"date/time field","errorType":"validation","errorClass":"ParserError","httpStatus":null,"severity":"error","filePath":"src/sqlparser/src/parser_v2/expr.rs","lineNumber":118,"sourceCode":"        data_type: data_type,\n        _: Token::RParen,\n    }});\n\n    trace(\"expr_try_cast\", parse).parse_next(input)\n}\n\n/// Consume a SQL EXTRACT function e.g. `EXTRACT(YEAR FROM expr)`\npub fn expr_extract<S>(input: &mut S) -> ModalResult<Expr>\nwhere\n    S: TokenStream,\n{\n    let mut date_time_field = token\n        .verify_map(|token| match token.token {\n            Token::Word(w) => Some(w.value.to_uppercase()),\n            Token::SingleQuotedString(s) => Some(s.to_uppercase()),\n            _ => None,\n        })\n        .expect(\"date/time field\");\n\n    let parse = cut_err(seq! {Expr::Extract {\n        _: Token::LParen,\n        field: date_time_field,\n        _: Keyword::FROM,\n        expr: expr_parse.map(Box::new),\n        _: Token::RParen,\n    }});\n\n    trace(\"expr_extract\", parse).parse_next(input)\n}\n\n/// Consume `SUBSTRING (EXPR [FROM 1] [FOR 3])`\npub fn expr_substring<S>(input: &mut S) -> ModalResult<Expr>\nwhere\n    S: TokenStream,\n{\n    let mut substring_from = opt(preceded(","sourceCodeStart":100,"sourceCodeEnd":136,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/sqlparser/src/parser_v2/expr.rs#L100-L136","documentation":"A panic message (via `.expect`) in the EXTRACT expression parser: the token after `EXTRACT` could not be read as a date/time field word or quoted string. It means the parser reached the field position but `verify_map` returned None, violating an internal assumption that a field token was present after the `cut_err` lookahead.","triggerScenarios":"Parsing `EXTRACT(` where the next token is not a Word or single-quoted string (e.g. `EXTRACT(123 FROM ts)` or `EXTRACT()`) — the `expect` panics instead of producing a normal parse error.","commonSituations":"Malformed SQL like `EXTRACT()` or `EXTRACT(1 FROM col)`; programmatic SQL generation with missing field; user typo placing a paren or number where the field name belongs.","solutions":["Provide a valid field name: `EXTRACT(YEAR FROM ts)` or `EXTRACT('year' FROM ts)`.","If you maintain the parser, replace `.expect` with a `cut_err`/context parse failure so it becomes a user-facing syntax error rather than a panic.","Validate SQL before submitting (lint with a parser that reports the missing field)."],"exampleFix":"// before\nEXTRACT(123 FROM ts)\n// after\nEXTRACT(YEAR FROM ts)","handlingStrategy":"validation","validationCode":"const FIELDS: [&str; 14] = [\"YEAR\",\"MONTH\",\"DAY\",\"HOUR\",\"MINUTE\",\"SECOND\",\"DOY\",\"DOW\",\"EPOCH\",\"WEEK\",\"QUARTER\",\"DECADE\",\"CENTURY\",\"MILLENNIUM\"];\nfn valid_extract_field(f: &str) -> bool { FIELDS.contains(&f.to_uppercase().as_str()) }","typeGuard":null,"tryCatchPattern":"// Panics, not Result: catch by validating SQL before parse, or wrap\nlet result = std::panic::catch_unwind(|| parse_extract(sql));\nif result.is_err() { /* report invalid EXTRACT field */ }","preventionTips":["Always pass a named date/time field as the first argument of EXTRACT.","Validate EXTRACT syntax in application SQL builders before sending.","Quote non-standard field names: EXTRACT('field' FROM ts)."],"tags":["sql-parser","panic","extract","internal-invariant"],"backgroundTag":"internal-invariant-violation","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"}