Skip to content

Let a Dialect override how a table name in FROM is parsed #2604

Description

@edmondop

Problem

Dialect can take over parsing at four points: parse_prefix, parse_infix, parse_statement, parse_column_option. Each returns Option<Result<_, ParserError>>, and None falls back to the default parser. Table references have no such hook: the plain-table branch of Parser::parse_table_factor unconditionally calls self.parse_object_name(true)?.

As a result, dialect-specific table-name syntax lives in the core parser behind hardcoded branches:

  • BigQuery's unquoted hyphenated names: dialect_of!(self is BigQueryDialect) && in_table_clause in parse_object_name_inner (the in_table_clause parameter exists only for this case).
  • Snowflake's @stage references: a supports_stages() branch in parse_table_factor calling parse_snowflake_stage_table_factor.

A downstream dialect with its own table-name syntax can't add a branch like these. The only option today is to tokenize, rewrite the token stream, and re-parse via Parser::with_tokens_with_locations: a second, token-level parser that can't see whether the parser is inside a FROM clause.

Motivation

Several tools hit this wall:

  • Engines that address tables as namespace:table, e.g. FROM events:analytics for table analytics in namespace events.
  • Tools parsing dbt SQL, where FROM clauses can contain {{ ref('model') }} or {{ source('schema', 'table') }} macros.
  • Any catalog with non-standard table addressing that a custom Dialect should parse natively instead of pre-processing.

Proposal

Add a hook with the same contract as the existing four:

/// Dialect-specific parser for the name of a table in a table factor.
///
/// If `None` is returned, falls back to the default behavior.
fn parse_table_factor_name(&self, _parser: &mut Parser) -> Option<Result<ObjectName, ParserError>> {
    None
}

parse_table_factor would call it where it calls parse_object_name(true) today. Everything after the name (JSON path, version, partitions, alias, sample, hints) stays in the core parser. The hook replaces only the name, so a dialect can't break alias or join parsing.

Alternatives considered

  • Hook all of parse_table_factor. More general, but a dialect that wants only new name syntax would have to reimplement aliases, TABLESAMPLE, and the rest.
  • Allow : through Dialect::is_identifier_part. Then events:analytics tokenizes as one identifier, but the colon becomes legal in every identifier position (so x:y also lexes as one identifier anywhere), and the result is a single Ident that callers must split after parsing.
  • Keep rewriting tokens before parsing. Works, but duplicates parsing logic at the token level without clause context.

Possible follow-up

BigQuery's hyphenated names could move onto this hook, which would let parse_object_name drop the in_table_clause parameter. That would demonstrate the hook covers syntax already in the tree.

No activity

Activity on this issue will appear here.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions