1515#[cfg(not(feature = "std"))]
1616use alloc::{
1717 boxed::Box,
18+ collections::BTreeMap,
1819 format,
1920 string::{String, ToString},
2021 vec,
@@ -24,6 +25,9 @@ use core::{
2425 fmt::{self, Display},
2526 str::FromStr,
2627};
28+ #[cfg(feature = "std")]
29+ use std::collections::BTreeMap;
30+
2731use helpers::attached_token::AttachedToken;
2832
2933use log::debug;
@@ -359,6 +363,29 @@ pub struct Parser<'a> {
359363 options: ParserOptions,
360364 /// Ensures the stack does not overflow by limiting recursion depth.
361365 recursion_counter: RecursionCounter,
366+ /// Cached failures from `parse_prefix` calls that returned `Err`. See
367+ /// [`Parser::parse_prefix`] for the 2^N patterns this guards.
368+ failed_prefix_positions: BTreeMap<usize, ExprPrefixError>,
369+ /// Cached failures from the speculative reserved-word prefix arm. See
370+ /// [`Parser::parse_prefix`] for the 2^N patterns this guards.
371+ failed_reserved_word_prefix_positions: BTreeMap<usize, ExprPrefixError>,
372+ }
373+
374+ /// Copy marker for a [`ParserError`] cached by the `parse_prefix` failure
375+ /// memoization, so the caches hold no strings.
376+ #[derive(Debug, Clone, Copy)]
377+ enum ExprPrefixError {
378+ RecursionLimitExceeded,
379+ Err,
380+ }
381+
382+ impl From<&ParserError> for ExprPrefixError {
383+ fn from(e: &ParserError) -> Self {
384+ match e {
385+ ParserError::RecursionLimitExceeded => Self::RecursionLimitExceeded,
386+ _ => Self::Err,
387+ }
388+ }
362389}
363390
364391impl<'a> Parser<'a> {
@@ -385,6 +412,8 @@ impl<'a> Parser<'a> {
385412 dialect,
386413 recursion_counter: RecursionCounter::new(DEFAULT_REMAINING_DEPTH),
387414 options: ParserOptions::new().with_trailing_commas(dialect.supports_trailing_commas()),
415+ failed_prefix_positions: BTreeMap::new(),
416+ failed_reserved_word_prefix_positions: BTreeMap::new(),
388417 }
389418 }
390419
@@ -446,6 +475,8 @@ impl<'a> Parser<'a> {
446475 pub fn with_tokens_with_locations(mut self, tokens: Vec<TokenWithSpan>) -> Self {
447476 self.tokens = tokens;
448477 self.index = 0;
478+ self.failed_prefix_positions.clear();
479+ self.failed_reserved_word_prefix_positions.clear();
449480 self
450481 }
451482
@@ -1717,6 +1748,35 @@ impl<'a> Parser<'a> {
17171748 return prefix;
17181749 }
17191750
1751+ // Memoize parse_prefix failures to break 2^N speculation when both
1752+ // prefix arms fail at every level (e.g. `IF(current_time(...x`).
1753+ // The per-arm cache in `parse_prefix_inner` complements this for
1754+ // chains where the reserved arm fails but the unreserved fallback
1755+ // succeeds (e.g. `case-case-...c`).
1756+ let start_index = self.index;
1757+ if let Some(&cached) = self.failed_prefix_positions.get(&start_index) {
1758+ return self.cached_prefix_error(cached, self.peek_token_ref());
1759+ }
1760+ let result = self.parse_prefix_inner();
1761+ if let Err(ref e) = result {
1762+ self.failed_prefix_positions.insert(start_index, e.into());
1763+ }
1764+ result
1765+ }
1766+
1767+ /// Rebuild the error for a cached prefix failure at the `found` token.
1768+ fn cached_prefix_error<T>(
1769+ &self,
1770+ cached: ExprPrefixError,
1771+ found: &TokenWithSpan,
1772+ ) -> Result<T, ParserError> {
1773+ match cached {
1774+ ExprPrefixError::RecursionLimitExceeded => Err(ParserError::RecursionLimitExceeded),
1775+ ExprPrefixError::Err => self.expected_ref("an expression", found),
1776+ }
1777+ }
1778+
1779+ fn parse_prefix_inner(&mut self) -> Result<Expr, ParserError> {
17201780 // PostgreSQL allows any string literal to be preceded by a type name, indicating that the
17211781 // string literal represents a literal of that type. Some examples:
17221782 //
@@ -1801,7 +1861,21 @@ impl<'a> Parser<'a> {
18011861 // We first try to parse the word and following tokens as a special expression, and if that fails,
18021862 // we rollback and try to parse it as an identifier.
18031863 let w = w.clone();
1804- match self.try_parse(|parser| parser.parse_expr_prefix_by_reserved_word(&w, span)) {
1864+ // Memoize failed speculative reserved-word parses. When
1865+ // the reserved arm (CASE, CURRENT_TIME, etc.) does
1866+ // exponential work but the unreserved fallback ultimately
1867+ // succeeds, the overall `parse_prefix` returns `Ok` and the
1868+ // outer cache never fires. Chains like `case-case-...c`
1869+ // need this per-arm cache to break the doubling.
1870+ let try_parse_result = if let Some(&cached) = self
1871+ .failed_reserved_word_prefix_positions
1872+ .get(&next_token_index)
1873+ {
1874+ self.cached_prefix_error(cached, self.get_current_token())
1875+ } else {
1876+ self.try_parse(|parser| parser.parse_expr_prefix_by_reserved_word(&w, span))
1877+ };
1878+ match try_parse_result {
18051879 // This word indicated an expression prefix and parsing was successful
18061880 Ok(Some(expr)) => Ok(expr),
18071881
@@ -1815,6 +1889,8 @@ impl<'a> Parser<'a> {
18151889 // we rollback and return the parsing error we got from trying to parse a
18161890 // special expression (to maintain backwards compatibility of parsing errors).
18171891 Err(e) => {
1892+ self.failed_reserved_word_prefix_positions
1893+ .insert(next_token_index, (&e).into());
18181894 if !self.dialect.is_reserved_for_identifier(w.keyword) {
18191895 if let Ok(Some(expr)) = self.maybe_parse(|parser| {
18201896 parser.parse_expr_prefix_by_unreserved_word(&w, span)
0 commit comments