Nyrox commented on code in PR #1435:
URL:
https://github.com/apache/datafusion-sqlparser-rs/pull/1435#discussion_r1802811502
##########
src/ast/spans.rs:
##########
@@ -0,0 +1,1798 @@
+use core::iter;
+
+use crate::tokenizer::Span;
+
+use super::{
+ AlterColumnOperation, AlterIndexOperation, AlterTableOperation, Array,
Assignment,
+ AssignmentTarget, CloseCursor, ClusteredIndex, ColumnDef, ColumnOption,
ColumnOptionDef,
+ ConflictTarget, ConstraintCharacteristics, CopySource, CreateIndex,
CreateTable,
+ CreateTableOptions, Cte, Delete, DoUpdate, ExceptSelectItem,
ExcludeSelectItem, Expr,
+ ExprWithAlias, FromTable, Function, FunctionArg, FunctionArgExpr,
FunctionArgumentClause,
+ FunctionArgumentList, FunctionArguments, GroupByExpr, HavingBound,
IlikeSelectItem, Insert,
+ Interpolate, InterpolateExpr, Join, JoinConstraint, JoinOperator,
JsonPath, JsonPathElem,
+ MatchRecognizePattern, Measure, ObjectName, OnConflict, OnConflictAction,
OnInsert, OrderBy,
+ OrderByExpr, Partition, PivotValueSource, ProjectionSelect, Query,
ReferentialAction,
+ RenameSelectItem, ReplaceSelectElement, ReplaceSelectItem, Select,
SelectItem, SetExpr,
+ SqlOption, Statement, Subscript, SymbolDefinition, TableAlias,
TableConstraint, TableFactor,
+ TableOptionsClustered, TableWithJoins, Use, Value, Values, ViewColumnDef,
+ WildcardAdditionalOptions, With, WithFill,
+};
+
+/// Given an iterator of spans, return the [Span::union] of all spans.
+fn union_spans<I: Iterator<Item = Span>>(iter: I) -> Span {
+ iter.reduce(|acc, item| acc.union(&item))
+ .unwrap_or(Span::empty())
+}
+
+/// A trait for AST nodes that have a source span for use in diagnostics.
+///
+/// Source spans are not guaranteed to be entirely accurate. They may
+/// be missing keywords or other tokens. Some nodes may not have a computable
+/// span at all, in which case they return [`Span::empty()`].
+///
+/// Some impl blocks may contain doc comments with information
+/// on which nodes are missing spans.
+pub trait Spanned {
+ /// Compute the source span for this AST node, by recursively
+ /// combining the spans of its children.
+ fn span(&self) -> Span;
+}
+
+impl Spanned for Query {
+ fn span(&self) -> Span {
+ self.body
+ .span()
+ .union_opt(&self.with.as_ref().map(|i| i.span()))
+ }
+}
+
+impl Spanned for With {
+ fn span(&self) -> Span {
+ union_spans(
+ core::iter::once(self.with_token.span)
+ .chain(self.cte_tables.iter().map(|item| item.span())),
+ )
+ }
+}
+
+impl Spanned for Cte {
+ fn span(&self) -> Span {
+ union_spans(
+ core::iter::once(self.alias.span())
+ .chain(core::iter::once(self.query.span()))
+ .chain(self.from.iter().map(|item| item.span))
+ .chain(core::iter::once(self.closing_paren_token.span)),
+ )
+ }
+}
+
+/// # partial span
+///
+/// [SetExpr::Table] is not implemented.
+impl Spanned for SetExpr {
+ fn span(&self) -> Span {
+ match self {
+ SetExpr::Select(select) => select.span(),
+ SetExpr::Query(query) => query.span(),
+ SetExpr::SetOperation {
+ op: _,
+ set_quantifier: _,
+ left,
+ right,
+ } => left.span().union(&right.span()),
+ SetExpr::Values(values) => values.span(),
+ SetExpr::Insert(statement) => statement.span(),
+ SetExpr::Table(_) => Span::empty(),
+ SetExpr::Update(statement) => statement.span(),
+ }
+ }
+}
+
+impl Spanned for Values {
+ fn span(&self) -> Span {
+ union_spans(
+ self.rows
+ .iter()
+ .map(|row| union_spans(row.iter().map(|expr| expr.span()))),
+ )
+ }
+}
+
+/// # partial span
+///
+/// Missing spans:
+/// - [Statement::CopyIntoSnowflake]
+/// - [Statement::CreateSecret]
+/// - [Statement::CreateRole]
+/// - [Statement::AlterRole]
+/// - [Statement::AttachDatabase]
+/// - [Statement::AttachDuckDBDatabase]
+/// - [Statement::DetachDuckDBDatabase]
+/// - [Statement::Drop]
+/// - [Statement::DropFunction]
+/// - [Statement::DropProcedure]
+/// - [Statement::DropSecret]
+/// - [Statement::Declare]
+/// - [Statement::CreateExtension]
+/// - [Statement::Fetch]
+/// - [Statement::Flush]
+/// - [Statement::Discard]
+/// - [Statement::SetRole]
+/// - [Statement::SetVariable]
+/// - [Statement::SetTimeZone]
+/// - [Statement::SetNames]
+/// - [Statement::SetNamesDefault]
+/// - [Statement::ShowFunctions]
+/// - [Statement::ShowVariable]
+/// - [Statement::ShowStatus]
+/// - [Statement::ShowVariables]
+/// - [Statement::ShowCreate]
+/// - [Statement::ShowColumns]
+/// - [Statement::ShowTables]
+/// - [Statement::ShowCollation]
+/// - [Statement::StartTransaction]
+/// - [Statement::SetTransaction]
+/// - [Statement::Comment]
+/// - [Statement::Commit]
+/// - [Statement::Rollback]
+/// - [Statement::CreateSchema]
+/// - [Statement::CreateDatabase]
+/// - [Statement::CreateFunction]
+/// - [Statement::CreateTrigger]
+/// - [Statement::DropTrigger]
+/// - [Statement::CreateProcedure]
+/// - [Statement::CreateMacro]
+/// - [Statement::CreateStage]
+/// - [Statement::Assert]
+/// - [Statement::Grant]
+/// - [Statement::Revoke]
+/// - [Statement::Deallocate]
+/// - [Statement::Execute]
+/// - [Statement::Prepare]
+/// - [Statement::Kill]
+/// - [Statement::ExplainTable]
+/// - [Statement::Explain]
+/// - [Statement::Savepoint]
+/// - [Statement::ReleaseSavepoint]
+/// - [Statement::Merge]
+/// - [Statement::Cache]
+/// - [Statement::UNCache]
+/// - [Statement::CreateSequence]
+/// - [Statement::CreateType]
+/// - [Statement::Pragma]
+/// - [Statement::LockTables]
+/// - [Statement::UnlockTables]
+/// - [Statement::Unload]
+/// - [Statement::OptimizeTable]
+impl Spanned for Statement {
+ fn span(&self) -> Span {
+ match self {
+ Statement::Analyze {
+ table_name,
+ partitions,
+ for_columns: _,
+ columns,
+ cache_metadata: _,
+ noscan: _,
+ compute_statistics: _,
+ } => union_spans(
+ core::iter::once(table_name.span())
+ .chain(partitions.iter().flat_map(|i| i.iter().map(|k|
k.span())))
+ .chain(columns.iter().map(|i| i.span)),
+ ),
+ Statement::Truncate {
+ table_names,
+ partitions,
+ table: _,
+ only: _,
+ identity: _,
+ cascade: _,
+ } => union_spans(
+ table_names
+ .iter()
+ .map(|i| i.name.span())
+ .chain(partitions.iter().flat_map(|i| i.iter().map(|k|
k.span()))),
+ ),
+ Statement::Msck {
+ table_name,
+ repair: _,
+ partition_action: _,
+ } => table_name.span(),
+ Statement::Query(query) => query.span(),
+ Statement::Insert(insert) => insert.span(),
+ Statement::Install { extension_name } => extension_name.span,
+ Statement::Load { extension_name } => extension_name.span,
+ Statement::Directory {
+ overwrite: _,
+ local: _,
+ path: _,
+ file_format: _,
+ source,
+ } => source.span(),
+ Statement::Call(function) => function.span(),
+ Statement::Copy {
+ source,
+ to: _,
+ target: _,
+ options: _,
+ legacy_options: _,
+ values: _,
+ } => source.span(),
+ Statement::CopyIntoSnowflake {
+ into: _,
+ from_stage: _,
+ from_stage_alias: _,
+ stage_params: _,
+ from_transformations: _,
+ files: _,
+ pattern: _,
+ file_format: _,
+ copy_options: _,
+ validation_mode: _,
+ } => Span::empty(),
+ Statement::Close { cursor } => match cursor {
+ CloseCursor::All => Span::empty(),
+ CloseCursor::Specific { name } => name.span,
+ },
+ Statement::Update {
+ table,
+ assignments,
+ from,
+ selection,
+ returning,
+ } => union_spans(
+ core::iter::once(table.span())
+ .chain(assignments.iter().map(|i| i.span()))
+ .chain(from.iter().map(|i| i.span()))
+ .chain(selection.iter().map(|i| i.span()))
+ .chain(returning.iter().flat_map(|i| i.iter().map(|k|
k.span()))),
+ ),
+ Statement::Delete(delete) => delete.span(),
+ Statement::CreateView {
+ or_replace: _,
+ materialized: _,
+ name,
+ columns,
+ query,
+ options,
+ cluster_by,
+ comment: _,
+ with_no_schema_binding: _,
+ if_not_exists: _,
+ temporary: _,
+ to,
+ } => union_spans(
+ core::iter::once(name.span())
+ .chain(columns.iter().map(|i| i.span()))
+ .chain(core::iter::once(query.span()))
+ .chain(core::iter::once(options.span()))
+ .chain(cluster_by.iter().map(|i| i.span))
+ .chain(to.iter().map(|i| i.span())),
+ ),
+ Statement::CreateTable(create_table) => create_table.span(),
+ Statement::CreateVirtualTable {
+ name,
+ if_not_exists: _,
+ module_name,
+ module_args,
+ } => union_spans(
+ core::iter::once(name.span())
+ .chain(core::iter::once(module_name.span))
+ .chain(module_args.iter().map(|i| i.span)),
+ ),
+ Statement::CreateIndex(create_index) => create_index.span(),
+ Statement::CreateRole { .. } => Span::empty(),
+ Statement::CreateSecret { .. } => Span::empty(),
+ Statement::AlterTable {
+ name,
+ if_exists: _,
+ only: _,
+ operations,
+ location: _,
+ on_cluster,
+ } => union_spans(
+ core::iter::once(name.span())
+ .chain(operations.iter().map(|i| i.span()))
+ .chain(on_cluster.iter().map(|i| i.span)),
+ ),
+ Statement::AlterIndex { name, operation } =>
name.span().union(&operation.span()),
+ Statement::AlterView {
+ name,
+ columns,
+ query,
+ with_options,
+ } => union_spans(
+ core::iter::once(name.span())
+ .chain(columns.iter().map(|i| i.span))
+ .chain(core::iter::once(query.span()))
+ .chain(with_options.iter().map(|i| i.span())),
+ ),
+ Statement::AlterRole { .. } => Span::empty(),
+ Statement::AttachDatabase { .. } => Span::empty(),
+ Statement::AttachDuckDBDatabase { .. } => Span::empty(),
+ Statement::DetachDuckDBDatabase { .. } => Span::empty(),
+ Statement::Drop { .. } => Span::empty(),
+ Statement::DropFunction { .. } => Span::empty(),
+ Statement::DropProcedure { .. } => Span::empty(),
+ Statement::DropSecret { .. } => Span::empty(),
+ Statement::Declare { .. } => Span::empty(),
+ Statement::CreateExtension { .. } => Span::empty(),
+ Statement::Fetch { .. } => Span::empty(),
+ Statement::Flush { .. } => Span::empty(),
+ Statement::Discard { .. } => Span::empty(),
+ Statement::SetRole { .. } => Span::empty(),
+ Statement::SetVariable { .. } => Span::empty(),
+ Statement::SetTimeZone { .. } => Span::empty(),
+ Statement::SetNames { .. } => Span::empty(),
+ Statement::SetNamesDefault {} => Span::empty(),
+ Statement::ShowFunctions { .. } => Span::empty(),
+ Statement::ShowVariable { .. } => Span::empty(),
+ Statement::ShowStatus { .. } => Span::empty(),
+ Statement::ShowVariables { .. } => Span::empty(),
+ Statement::ShowCreate { .. } => Span::empty(),
+ Statement::ShowColumns { .. } => Span::empty(),
+ Statement::ShowTables { .. } => Span::empty(),
+ Statement::ShowCollation { .. } => Span::empty(),
+ Statement::Use(u) => u.span(),
+ Statement::StartTransaction { .. } => Span::empty(),
+ Statement::SetTransaction { .. } => Span::empty(),
+ Statement::Comment { .. } => Span::empty(),
+ Statement::Commit { .. } => Span::empty(),
+ Statement::Rollback { .. } => Span::empty(),
+ Statement::CreateSchema { .. } => Span::empty(),
+ Statement::CreateDatabase { .. } => Span::empty(),
+ Statement::CreateFunction { .. } => Span::empty(),
+ Statement::CreateTrigger { .. } => Span::empty(),
+ Statement::DropTrigger { .. } => Span::empty(),
+ Statement::CreateProcedure { .. } => Span::empty(),
+ Statement::CreateMacro { .. } => Span::empty(),
+ Statement::CreateStage { .. } => Span::empty(),
+ Statement::Assert { .. } => Span::empty(),
+ Statement::Grant { .. } => Span::empty(),
+ Statement::Revoke { .. } => Span::empty(),
+ Statement::Deallocate { .. } => Span::empty(),
+ Statement::Execute { .. } => Span::empty(),
+ Statement::Prepare { .. } => Span::empty(),
+ Statement::Kill { .. } => Span::empty(),
+ Statement::ExplainTable { .. } => Span::empty(),
+ Statement::Explain { .. } => Span::empty(),
+ Statement::Savepoint { .. } => Span::empty(),
+ Statement::ReleaseSavepoint { .. } => Span::empty(),
+ Statement::Merge { .. } => Span::empty(),
+ Statement::Cache { .. } => Span::empty(),
+ Statement::UNCache { .. } => Span::empty(),
+ Statement::CreateSequence { .. } => Span::empty(),
+ Statement::CreateType { .. } => Span::empty(),
+ Statement::Pragma { .. } => Span::empty(),
+ Statement::LockTables { .. } => Span::empty(),
+ Statement::UnlockTables => Span::empty(),
+ Statement::Unload { .. } => Span::empty(),
+ Statement::OptimizeTable { .. } => Span::empty(),
+ }
+ }
+}
+
+impl Spanned for Use {
+ fn span(&self) -> Span {
+ match self {
+ Use::Catalog(object_name) => object_name.span(),
+ Use::Schema(object_name) => object_name.span(),
+ Use::Database(object_name) => object_name.span(),
+ Use::Warehouse(object_name) => object_name.span(),
+ Use::Object(object_name) => object_name.span(),
+ Use::Default => Span::empty(),
+ }
+ }
+}
+
+impl Spanned for CreateTable {
+ fn span(&self) -> Span {
+ union_spans(
+ core::iter::once(self.name.span())
+ .chain(self.columns.iter().map(|i| i.span()))
+ .chain(self.constraints.iter().map(|i| i.span()))
+ .chain(self.table_properties.iter().map(|i| i.span()))
+ .chain(self.with_options.iter().map(|i| i.span()))
+ .chain(self.query.iter().map(|i| i.span()))
+ .chain(self.like.iter().map(|i| i.span()))
+ .chain(self.clone.iter().map(|i| i.span())),
+ )
+ }
+}
+
+impl Spanned for ColumnDef {
+ fn span(&self) -> Span {
+ union_spans(
+ core::iter::once(self.name.span)
+ .chain(self.collation.iter().map(|i| i.span()))
+ .chain(self.options.iter().map(|i| i.span())),
+ )
+ }
+}
+
+impl Spanned for ColumnOptionDef {
+ fn span(&self) -> Span {
+ self.option
+ .span()
+ .union_opt(&self.name.as_ref().map(|i| i.span))
+ }
+}
+
+impl Spanned for TableConstraint {
+ fn span(&self) -> Span {
+ match self {
+ TableConstraint::Unique {
+ name,
+ index_name,
+ index_type_display: _,
+ index_type: _,
+ columns,
+ index_options: _,
+ characteristics,
+ } => union_spans(
+ name.iter()
+ .map(|i| i.span)
+ .chain(index_name.iter().map(|i| i.span))
+ .chain(columns.iter().map(|i| i.span))
+ .chain(characteristics.iter().map(|i| i.span())),
+ ),
+ TableConstraint::PrimaryKey {
+ name,
+ index_name,
+ index_type: _,
+ columns,
+ index_options: _,
+ characteristics,
+ } => union_spans(
+ name.iter()
+ .map(|i| i.span)
+ .chain(index_name.iter().map(|i| i.span))
+ .chain(columns.iter().map(|i| i.span))
+ .chain(characteristics.iter().map(|i| i.span())),
+ ),
+ TableConstraint::ForeignKey {
+ name,
+ columns,
+ foreign_table,
+ referred_columns,
+ on_delete,
+ on_update,
+ characteristics,
+ } => union_spans(
+ name.iter()
+ .map(|i| i.span)
+ .chain(columns.iter().map(|i| i.span))
+ .chain(core::iter::once(foreign_table.span()))
+ .chain(referred_columns.iter().map(|i| i.span))
+ .chain(on_delete.iter().map(|i| i.span()))
+ .chain(on_update.iter().map(|i| i.span()))
+ .chain(characteristics.iter().map(|i| i.span())),
+ ),
+ TableConstraint::Check { name, expr } => {
+ expr.span().union_opt(&name.as_ref().map(|i| i.span))
+ }
+ TableConstraint::Index {
+ display_as_key: _,
+ name,
+ index_type: _,
+ columns,
+ } => union_spans(
+ name.iter()
+ .map(|i| i.span)
+ .chain(columns.iter().map(|i| i.span)),
+ ),
+ TableConstraint::FulltextOrSpatial {
+ fulltext: _,
+ index_type_display: _,
+ opt_index_name,
+ columns,
+ } => union_spans(
+ opt_index_name
+ .iter()
+ .map(|i| i.span)
+ .chain(columns.iter().map(|i| i.span)),
+ ),
+ }
+ }
+}
+
+impl Spanned for CreateIndex {
+ fn span(&self) -> Span {
+ union_spans(
+ self.name
+ .iter()
+ .map(|i| i.span())
+ .chain(core::iter::once(self.table_name.span()))
+ .chain(self.using.iter().map(|i| i.span))
+ .chain(self.columns.iter().map(|i| i.span()))
+ .chain(self.include.iter().map(|i| i.span))
+ .chain(self.with.iter().map(|i| i.span()))
+ .chain(self.predicate.iter().map(|i| i.span())),
+ )
+ }
+}
+
+/// # partial span
+///
+/// Missing spans:
+/// - [ColumnOption::Null]
+/// - [ColumnOption::NotNull]
+/// - [ColumnOption::Comment]
+/// - [ColumnOption::Unique]ยจ
+/// - [ColumnOption::DialectSpecific]
+/// - [ColumnOption::Generated]
+impl Spanned for ColumnOption {
+ fn span(&self) -> Span {
+ match self {
+ ColumnOption::Null => Span::empty(),
+ ColumnOption::NotNull => Span::empty(),
+ ColumnOption::Default(expr) => expr.span(),
+ ColumnOption::Materialized(expr) => expr.span(),
+ ColumnOption::Ephemeral(expr) =>
expr.as_ref().map_or(Span::empty(), |e| e.span()),
+ ColumnOption::Alias(expr) => expr.span(),
+ ColumnOption::Unique { .. } => Span::empty(),
+ ColumnOption::ForeignKey {
+ foreign_table,
+ referred_columns,
+ on_delete,
+ on_update,
+ characteristics,
+ } => union_spans(
+ core::iter::once(foreign_table.span())
+ .chain(referred_columns.iter().map(|i| i.span))
+ .chain(on_delete.iter().map(|i| i.span()))
+ .chain(on_update.iter().map(|i| i.span()))
+ .chain(characteristics.iter().map(|i| i.span())),
+ ),
+ ColumnOption::Check(expr) => expr.span(),
+ ColumnOption::DialectSpecific(_) => Span::empty(),
+ ColumnOption::CharacterSet(object_name) => object_name.span(),
+ ColumnOption::Comment(_) => Span::empty(),
+ ColumnOption::OnUpdate(expr) => expr.span(),
+ ColumnOption::Generated { .. } => Span::empty(),
+ ColumnOption::Options(vec) => union_spans(vec.iter().map(|i|
i.span())),
+ }
+ }
+}
+
+/// # missing span
+impl Spanned for ReferentialAction {
+ fn span(&self) -> Span {
+ Span::empty()
+ }
+}
+
+/// # missing span
+impl Spanned for ConstraintCharacteristics {
+ fn span(&self) -> Span {
+ Span::empty()
+ }
+}
+
+/// # partial span
+///
+/// Missing spans:
+/// - [AlterColumnOperation::SetNotNull]
+/// - [AlterColumnOperation::DropNotNull]
+/// - [AlterColumnOperation::DropDefault]
+/// - [AlterColumnOperation::AddGenerated]
+impl Spanned for AlterColumnOperation {
+ fn span(&self) -> Span {
+ match self {
+ AlterColumnOperation::SetNotNull => Span::empty(),
+ AlterColumnOperation::DropNotNull => Span::empty(),
+ AlterColumnOperation::SetDefault { value } => value.span(),
+ AlterColumnOperation::DropDefault => Span::empty(),
+ AlterColumnOperation::SetDataType {
+ data_type: _,
+ using,
+ } => using.as_ref().map_or(Span::empty(), |u| u.span()),
+ AlterColumnOperation::AddGenerated { .. } => Span::empty(),
+ }
+ }
+}
+
+impl Spanned for CopySource {
+ fn span(&self) -> Span {
+ match self {
+ CopySource::Table {
+ table_name,
+ columns,
+ } => union_spans(
+
core::iter::once(table_name.span()).chain(columns.iter().map(|i| i.span)),
+ ),
+ CopySource::Query(query) => query.span(),
+ }
+ }
+}
+
+impl Spanned for Delete {
+ fn span(&self) -> Span {
+ union_spans(
+ self.tables
+ .iter()
+ .map(|i| i.span())
+ .chain(core::iter::once(self.from.span()))
+ .chain(
+ self.using
+ .iter()
+ .map(|u| union_spans(u.iter().map(|i| i.span()))),
+ )
+ .chain(self.selection.iter().map(|i| i.span()))
+ .chain(
+ self.returning
+ .iter()
+ .flat_map(|i| i.iter().map(|k| k.span())),
+ )
+ .chain(self.order_by.iter().map(|i| i.span()))
+ .chain(self.limit.iter().map(|i| i.span())),
+ )
+ }
+}
+
+impl Spanned for FromTable {
+ fn span(&self) -> Span {
+ match self {
+ FromTable::WithFromKeyword(vec) => union_spans(vec.iter().map(|i|
i.span())),
+ FromTable::WithoutKeyword(vec) => union_spans(vec.iter().map(|i|
i.span())),
+ }
+ }
+}
+
+impl Spanned for ViewColumnDef {
+ fn span(&self) -> Span {
+ union_spans(
+ core::iter::once(self.name.span)
+ .chain(self.options.iter().flat_map(|i| i.iter().map(|k|
k.span()))),
+ )
+ }
+}
+
+impl Spanned for SqlOption {
+ fn span(&self) -> Span {
+ match self {
+ SqlOption::Clustered(table_options_clustered) =>
table_options_clustered.span(),
+ SqlOption::Ident(ident) => ident.span,
+ SqlOption::KeyValue { key, value } =>
key.span.union(&value.span()),
+ SqlOption::Partition {
+ column_name,
+ range_direction: _,
+ for_values,
+ } => union_spans(
+
core::iter::once(column_name.span).chain(for_values.iter().map(|i| i.span())),
+ ),
+ }
+ }
+}
+
+/// # partial span
+///
+/// Missing spans:
+/// - [TableOptionsClustered::ColumnstoreIndex]
+impl Spanned for TableOptionsClustered {
+ fn span(&self) -> Span {
+ match self {
+ TableOptionsClustered::ColumnstoreIndex => Span::empty(),
+ TableOptionsClustered::ColumnstoreIndexOrder(vec) => {
+ union_spans(vec.iter().map(|i| i.span))
+ }
+ TableOptionsClustered::Index(vec) =>
union_spans(vec.iter().map(|i| i.span())),
+ }
+ }
+}
+
+impl Spanned for ClusteredIndex {
+ fn span(&self) -> Span {
+ self.name.span
+ }
+}
+
+impl Spanned for CreateTableOptions {
+ fn span(&self) -> Span {
+ match self {
+ CreateTableOptions::None => Span::empty(),
+ CreateTableOptions::With(vec) => union_spans(vec.iter().map(|i|
i.span())),
+ CreateTableOptions::Options(vec) => union_spans(vec.iter().map(|i|
i.span())),
+ }
+ }
+}
+
+/// # partial span
+///
+/// Missing spans:
+/// - [AlterTableOperation::OwnerTo]
+impl Spanned for AlterTableOperation {
+ fn span(&self) -> Span {
+ match self {
+ AlterTableOperation::AddConstraint(table_constraint) =>
table_constraint.span(),
+ AlterTableOperation::AddColumn {
+ column_keyword: _,
+ if_not_exists: _,
+ column_def,
+ column_position: _,
+ } => column_def.span(),
+ AlterTableOperation::AddProjection {
+ if_not_exists: _,
+ name,
+ select,
+ } => name.span.union(&select.span()),
+ AlterTableOperation::DropProjection { if_exists: _, name } =>
name.span,
+ AlterTableOperation::MaterializeProjection {
+ if_exists: _,
+ name,
+ partition,
+ } => name.span.union_opt(&partition.as_ref().map(|i| i.span)),
+ AlterTableOperation::ClearProjection {
+ if_exists: _,
+ name,
+ partition,
+ } => name.span.union_opt(&partition.as_ref().map(|i| i.span)),
+ AlterTableOperation::DisableRowLevelSecurity => Span::empty(),
+ AlterTableOperation::DisableRule { name } => name.span,
+ AlterTableOperation::DisableTrigger { name } => name.span,
+ AlterTableOperation::DropConstraint {
+ if_exists: _,
+ name,
+ cascade: _,
+ } => name.span,
+ AlterTableOperation::DropColumn {
+ column_name,
+ if_exists: _,
+ cascade: _,
+ } => column_name.span,
+ AlterTableOperation::AttachPartition { partition } =>
partition.span(),
+ AlterTableOperation::DetachPartition { partition } =>
partition.span(),
+ AlterTableOperation::FreezePartition {
+ partition,
+ with_name,
+ } => partition
+ .span()
+ .union_opt(&with_name.as_ref().map(|n| n.span)),
+ AlterTableOperation::UnfreezePartition {
+ partition,
+ with_name,
+ } => partition
+ .span()
+ .union_opt(&with_name.as_ref().map(|n| n.span)),
+ AlterTableOperation::DropPrimaryKey => Span::empty(),
+ AlterTableOperation::EnableAlwaysRule { name } => name.span,
+ AlterTableOperation::EnableAlwaysTrigger { name } => name.span,
+ AlterTableOperation::EnableReplicaRule { name } => name.span,
+ AlterTableOperation::EnableReplicaTrigger { name } => name.span,
+ AlterTableOperation::EnableRowLevelSecurity => Span::empty(),
+ AlterTableOperation::EnableRule { name } => name.span,
+ AlterTableOperation::EnableTrigger { name } => name.span,
+ AlterTableOperation::RenamePartitions {
+ old_partitions,
+ new_partitions,
+ } => union_spans(
+ old_partitions
+ .iter()
+ .map(|i| i.span())
+ .chain(new_partitions.iter().map(|i| i.span())),
+ ),
+ AlterTableOperation::AddPartitions {
+ if_not_exists: _,
+ new_partitions,
+ } => union_spans(new_partitions.iter().map(|i| i.span())),
+ AlterTableOperation::DropPartitions {
+ partitions,
+ if_exists: _,
+ } => union_spans(partitions.iter().map(|i| i.span())),
+ AlterTableOperation::RenameColumn {
+ old_column_name,
+ new_column_name,
+ } => old_column_name.span.union(&new_column_name.span),
+ AlterTableOperation::RenameTable { table_name } =>
table_name.span(),
+ AlterTableOperation::ChangeColumn {
+ old_name,
+ new_name,
+ data_type: _,
+ options,
+ column_position: _,
+ } => union_spans(
+ core::iter::once(old_name.span)
+ .chain(core::iter::once(new_name.span))
+ .chain(options.iter().map(|i| i.span())),
+ ),
+ AlterTableOperation::ModifyColumn {
+ col_name,
+ data_type: _,
+ options,
+ column_position: _,
+ } => {
+
union_spans(core::iter::once(col_name.span).chain(options.iter().map(|i|
i.span())))
+ }
+ AlterTableOperation::RenameConstraint { old_name, new_name } => {
+ old_name.span.union(&new_name.span)
+ }
+ AlterTableOperation::AlterColumn { column_name, op } => {
+ column_name.span.union(&op.span())
+ }
+ AlterTableOperation::SwapWith { table_name } => table_name.span(),
+ AlterTableOperation::SetTblProperties { table_properties } => {
+ union_spans(table_properties.iter().map(|i| i.span()))
+ }
+ AlterTableOperation::OwnerTo { .. } => Span::empty(),
+ }
+ }
+}
+
+impl Spanned for Partition {
+ fn span(&self) -> Span {
+ match self {
+ Partition::Identifier(ident) => ident.span,
+ Partition::Expr(expr) => expr.span(),
+ Partition::Part(expr) => expr.span(),
+ Partition::Partitions(vec) => union_spans(vec.iter().map(|i|
i.span())),
+ }
+ }
+}
+
+impl Spanned for ProjectionSelect {
+ fn span(&self) -> Span {
+ union_spans(
+ self.projection
+ .iter()
+ .map(|i| i.span())
+ .chain(self.order_by.iter().map(|i| i.span()))
+ .chain(self.group_by.iter().map(|i| i.span())),
+ )
+ }
+}
+
+impl Spanned for OrderBy {
+ fn span(&self) -> Span {
+ union_spans(
+ self.exprs
+ .iter()
+ .map(|i| i.span())
+ .chain(self.interpolate.iter().map(|i| i.span())),
+ )
+ }
+}
+
+/// # partial span
+///
+/// Missing spans:
+/// - [GroupByExpr::All]
+impl Spanned for GroupByExpr {
+ fn span(&self) -> Span {
+ match self {
+ GroupByExpr::All(_) => Span::empty(),
+ GroupByExpr::Expressions(exprs, _modifiers) => {
+ union_spans(exprs.iter().map(|i| i.span()))
+ }
+ }
+ }
+}
+
+impl Spanned for Interpolate {
+ fn span(&self) -> Span {
+ union_spans(self.exprs.iter().flat_map(|i| i.iter().map(|e| e.span())))
+ }
+}
+
+impl Spanned for InterpolateExpr {
+ fn span(&self) -> Span {
+ self.column
+ .span
+ .union_opt(&self.expr.as_ref().map(|e| e.span()))
+ }
+}
+
+impl Spanned for AlterIndexOperation {
+ fn span(&self) -> Span {
+ match self {
+ AlterIndexOperation::RenameIndex { index_name } =>
index_name.span(),
+ }
+ }
+}
+
+/// # partial span
+///
+/// Missing spans:ever
+/// - [Insert::insert_alias]
+impl Spanned for Insert {
+ fn span(&self) -> Span {
+ union_spans(
+ core::iter::once(self.table_name.span())
+ .chain(self.table_alias.as_ref().map(|i| i.span))
+ .chain(self.columns.iter().map(|i| i.span))
+ .chain(self.source.as_ref().map(|q| q.span()))
+ .chain(
+ self.partitioned
+ .iter()
+ .flat_map(|i| i.iter().map(|k| k.span())),
+ )
+ .chain(self.after_columns.iter().map(|i| i.span))
+ .chain(self.on.as_ref().map(|i| i.span()))
+ .chain(
+ self.returning
+ .iter()
+ .flat_map(|i| i.iter().map(|k| k.span())),
+ ),
+ )
+ }
+}
+
+impl Spanned for OnInsert {
+ fn span(&self) -> Span {
+ match self {
+ OnInsert::DuplicateKeyUpdate(vec) =>
union_spans(vec.iter().map(|i| i.span())),
+ OnInsert::OnConflict(on_conflict) => on_conflict.span(),
+ }
+ }
+}
+
+impl Spanned for OnConflict {
+ fn span(&self) -> Span {
+ self.action
+ .span()
+ .union_opt(&self.conflict_target.as_ref().map(|i| i.span()))
+ }
+}
+
+impl Spanned for ConflictTarget {
+ fn span(&self) -> Span {
+ match self {
+ ConflictTarget::Columns(vec) => union_spans(vec.iter().map(|i|
i.span)),
+ ConflictTarget::OnConstraint(object_name) => object_name.span(),
+ }
+ }
+}
+
+/// # partial span
+///
+/// Missing spans:
+/// - [OnConflictAction::DoNothing]
+impl Spanned for OnConflictAction {
+ fn span(&self) -> Span {
+ match self {
+ OnConflictAction::DoNothing => Span::empty(),
+ OnConflictAction::DoUpdate(do_update) => do_update.span(),
+ }
+ }
+}
+
+impl Spanned for DoUpdate {
+ fn span(&self) -> Span {
+ union_spans(
+ self.assignments
+ .iter()
+ .map(|i| i.span())
+ .chain(self.selection.iter().map(|i| i.span())),
+ )
+ }
+}
+
+impl Spanned for Assignment {
+ fn span(&self) -> Span {
+ self.target.span().union(&self.value.span())
+ }
+}
+
+impl Spanned for AssignmentTarget {
+ fn span(&self) -> Span {
+ match self {
+ AssignmentTarget::ColumnName(object_name) => object_name.span(),
+ AssignmentTarget::Tuple(vec) => union_spans(vec.iter().map(|i|
i.span())),
+ }
+ }
+}
+
+/// # partial span
+///
+/// Most expressions are missing keywords in their spans.
+/// f.e. `IS NULL <expr>` reports as `<expr>::span`.
+///
+/// Missing spans:
+/// - [Expr::TypedString]
+/// - [Expr::MatchAgainst] # MySQL specific
+/// - [Expr::RLike] # MySQL specific
+/// - [Expr::Struct] # BigQuery specific
+/// - [Expr::Named] # BigQuery specific
+/// - [Expr::Dictionary] # DuckDB specific
+/// - [Expr::Map] # DuckDB specific
+/// - [Expr::Lambda]
+impl Spanned for Expr {
+ fn span(&self) -> Span {
+ match self {
+ Expr::Identifier(ident) => ident.span,
+ Expr::CompoundIdentifier(vec) => union_spans(vec.iter().map(|i|
i.span)),
+ Expr::CompositeAccess { expr, key } =>
expr.span().union(&key.span),
+ Expr::IsFalse(expr) => expr.span(),
+ Expr::IsNotFalse(expr) => expr.span(),
+ Expr::IsTrue(expr) => expr.span(),
+ Expr::IsNotTrue(expr) => expr.span(),
+ Expr::IsNull(expr) => expr.span(),
+ Expr::IsNotNull(expr) => expr.span(),
+ Expr::IsUnknown(expr) => expr.span(),
+ Expr::IsNotUnknown(expr) => expr.span(),
+ Expr::IsDistinctFrom(lhs, rhs) => lhs.span().union(&rhs.span()),
+ Expr::IsNotDistinctFrom(lhs, rhs) => lhs.span().union(&rhs.span()),
+ Expr::InList {
+ expr,
+ list,
+ negated: _,
+ } => union_spans(
+ core::iter::once(expr.span()).chain(list.iter().map(|item|
item.span())),
+ ),
+ Expr::InSubquery {
+ expr,
+ subquery,
+ negated: _,
+ } => expr.span().union(&subquery.span()),
+ Expr::InUnnest {
+ expr,
+ array_expr,
+ negated: _,
+ } => expr.span().union(&array_expr.span()),
+ Expr::Between {
+ expr,
+ negated: _,
+ low,
+ high,
+ } => expr.span().union(&low.span()).union(&high.span()),
+
+ Expr::BinaryOp { left, op: _, right } =>
left.span().union(&right.span()),
+ Expr::Like {
+ negated: _,
+ expr,
+ pattern,
+ escape_char: _,
+ } => expr.span().union(&pattern.span()),
+ Expr::ILike {
+ negated: _,
+ expr,
+ pattern,
+ escape_char: _,
+ } => expr.span().union(&pattern.span()),
+ Expr::SimilarTo {
+ negated: _,
+ expr,
+ pattern,
+ escape_char: _,
+ } => expr.span().union(&pattern.span()),
+ Expr::Ceil { expr, field: _ } => expr.span(),
+ Expr::Floor { expr, field: _ } => expr.span(),
+ Expr::Position { expr, r#in } => expr.span().union(&r#in.span()),
+ Expr::Overlay {
+ expr,
+ overlay_what,
+ overlay_from,
+ overlay_for,
+ } => expr
+ .span()
+ .union(&overlay_what.span())
+ .union(&overlay_from.span())
+ .union_opt(&overlay_for.as_ref().map(|i| i.span())),
+ Expr::Collate { expr, collation } => expr
+ .span()
+ .union(&union_spans(collation.0.iter().map(|i| i.span))),
+ Expr::Nested(expr) => expr.span(),
+ Expr::Value(value) => value.span(),
+ Expr::TypedString { .. } => Span::empty(),
+ Expr::MapAccess { column, keys } => column
+ .span()
+ .union(&union_spans(keys.iter().map(|i| i.key.span()))),
+ Expr::Function(function) => function.span(),
+ Expr::GroupingSets(vec) => {
+ union_spans(vec.iter().flat_map(|i| i.iter().map(|k|
k.span())))
+ }
+ Expr::Cube(vec) => union_spans(vec.iter().flat_map(|i|
i.iter().map(|k| k.span()))),
+ Expr::Rollup(vec) => union_spans(vec.iter().flat_map(|i|
i.iter().map(|k| k.span()))),
+ Expr::Tuple(vec) => union_spans(vec.iter().map(|i| i.span())),
+ Expr::Array(array) => array.span(),
+ Expr::MatchAgainst { .. } => Span::empty(),
+ Expr::JsonAccess { value, path } =>
value.span().union(&path.span()),
+ Expr::RLike { .. } => Span::empty(),
+ Expr::AnyOp {
+ left,
+ compare_op: _,
+ right,
+ } => left.span().union(&right.span()),
+ Expr::AllOp {
+ left,
+ compare_op: _,
+ right,
+ } => left.span().union(&right.span()),
+ Expr::UnaryOp { op: _, expr } => expr.span(),
+ Expr::Convert {
+ expr,
+ data_type: _,
+ charset,
+ target_before_value: _,
+ styles,
+ } => union_spans(
+ core::iter::once(expr.span())
+ .chain(charset.as_ref().map(|i| i.span()))
+ .chain(styles.iter().map(|i| i.span())),
+ ),
+ Expr::Cast {
+ kind: _,
+ expr,
+ data_type: _,
+ format: _,
+ } => expr.span(),
+ Expr::AtTimeZone {
+ timestamp,
+ time_zone,
+ } => timestamp.span().union(&time_zone.span()),
+ Expr::Extract {
+ field: _,
+ syntax: _,
+ expr,
+ } => expr.span(),
+ Expr::Substring {
+ expr,
+ substring_from,
+ substring_for,
+ special: _,
+ } => union_spans(
+ core::iter::once(expr.span())
+ .chain(substring_from.as_ref().map(|i| i.span()))
+ .chain(substring_for.as_ref().map(|i| i.span())),
+ ),
+ Expr::Trim {
+ expr,
+ trim_where: _,
+ trim_what,
+ trim_characters,
+ } => union_spans(
+ core::iter::once(expr.span())
+ .chain(trim_what.as_ref().map(|i| i.span()))
+ .chain(
+ trim_characters
+ .as_ref()
+ .map(|items| union_spans(items.iter().map(|i|
i.span()))),
+ ),
+ ),
+ Expr::IntroducedString { value, .. } => value.span(),
+ Expr::Case {
+ operand,
+ conditions,
+ results,
+ else_result,
+ } => union_spans(
+ operand
+ .as_ref()
+ .map(|i| i.span())
+ .into_iter()
+ .chain(conditions.iter().map(|i| i.span()))
+ .chain(results.iter().map(|i| i.span()))
+ .chain(else_result.as_ref().map(|i| i.span())),
+ ),
+ Expr::Exists { subquery, .. } => subquery.span(),
+ Expr::Subquery(query) => query.span(),
+ Expr::Struct { .. } => Span::empty(),
+ Expr::Named { .. } => Span::empty(),
+ Expr::Dictionary(_) => Span::empty(),
+ Expr::Map(_) => Span::empty(),
+ Expr::Subscript { expr, subscript } =>
expr.span().union(&subscript.span()),
+ Expr::Interval(interval) => interval.value.span(),
+ Expr::Wildcard(token) => token.span,
+ Expr::QualifiedWildcard(object_name, token) => union_spans(
+ object_name
+ .0
+ .iter()
+ .map(|i| i.span)
+ .chain(iter::once(token.span)),
+ ),
+ Expr::OuterJoin(expr) => expr.span(),
+ Expr::Prior(expr) => expr.span(),
+ Expr::Lambda(_) => Span::empty(),
+ }
+ }
+}
+
+impl Spanned for Subscript {
+ fn span(&self) -> Span {
+ match self {
+ Subscript::Index { index } => index.span(),
+ Subscript::Slice {
+ lower_bound,
+ upper_bound,
+ stride,
+ } => union_spans(
+ [
+ lower_bound.as_ref().map(|i| i.span()),
+ upper_bound.as_ref().map(|i| i.span()),
+ stride.as_ref().map(|i| i.span()),
+ ]
+ .iter()
+ .flatten()
+ .cloned(),
+ ),
+ }
+ }
+}
+
+impl Spanned for ObjectName {
+ fn span(&self) -> Span {
+ union_spans(self.0.iter().map(|i| i.span))
+ }
+}
+
+impl Spanned for Array {
+ fn span(&self) -> Span {
+ union_spans(self.elem.iter().map(|i| i.span()))
+ }
+}
+
+impl Spanned for Function {
+ fn span(&self) -> Span {
+ union_spans(
+ self.name
+ .0
+ .iter()
+ .map(|i| i.span)
+ .chain(iter::once(self.args.span())),
+ )
Review Comment:
Done. Thanks for the suggestion, I'll definitely stash this technique in my
memory. ๐
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]