blob: c0b52977e14a94c86369e8041f5edf57c7474e0d [file]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
use std::cmp::{self, Ordering};
use std::fmt;
use std::hash::{Hash, Hasher};
/// Represents a location, determined by a line and a column number, in the
/// original SQL query.
#[derive(Eq, PartialEq, Hash, Clone, Copy, Ord, PartialOrd)]
pub struct Location {
/// Line number, starting from 1.
///
/// Note: Line 0 is used for empty spans
pub line: u64,
/// Line column, starting from 1.
///
/// Note: Column 0 is used for empty spans
pub column: u64,
}
impl fmt::Debug for Location {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Location({},{})", self.line, self.column)
}
}
#[cfg(feature = "sql")]
impl From<sqlparser::tokenizer::Location> for Location {
fn from(value: sqlparser::tokenizer::Location) -> Self {
Self {
line: value.line,
column: value.column,
}
}
}
/// Represents an interval of characters in the original SQL query.
#[derive(Eq, PartialEq, Hash, Clone, PartialOrd, Ord, Copy)]
pub struct Span {
pub start: Location,
pub end: Location,
}
impl fmt::Debug for Span {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Span({:?}..{:?})", self.start, self.end)
}
}
impl Span {
/// Creates a new [`Span`] from a start and an end [`Location`].
pub fn new(start: Location, end: Location) -> Self {
Self { start, end }
}
/// Convert a [`Span`](sqlparser::tokenizer::Span) from the parser, into a
/// DataFusion [`Span`]. If the input span is empty (line 0 column 0, to
/// line 0 column 0), then [`None`] is returned.
#[cfg(feature = "sql")]
pub fn try_from_sqlparser_span(span: sqlparser::tokenizer::Span) -> Option<Span> {
if span == sqlparser::tokenizer::Span::empty() {
None
} else {
Some(Span {
start: span.start.into(),
end: span.end.into(),
})
}
}
/// Returns the smallest Span that contains both `self` and `other`
///
/// # Examples
/// ```
/// # use sqlparser::tokenizer::{Span, Location};
/// // line 1, column1 -> line 2, column 5
/// let span1 = Span::new(Location::new(1, 1), Location::new(2, 5));
/// // line 2, column 3 -> line 3, column 7
/// let span2 = Span::new(Location::new(2, 3), Location::new(3, 7));
/// // Union of the two is the min/max of the two spans
/// // line 1, column 1 -> line 3, column 7
/// let union = span1.union(&span2);
/// assert_eq!(union, Span::new(Location::new(1, 1), Location::new(3, 7)));
/// ```
pub fn union(&self, other: &Span) -> Span {
Span {
start: cmp::min(self.start, other.start),
end: cmp::max(self.end, other.end),
}
}
/// Same as [Span::union] for `Option<Span>`.
///
/// If `other` is `None`, `self` is returned.
pub fn union_opt(&self, other: &Option<Span>) -> Span {
match other {
Some(other) => self.union(other),
None => *self,
}
}
/// Return the [Span::union] of all spans in the iterator.
///
/// If the iterator is empty, [`None`] is returned.
///
/// # Example
/// ```
/// # use sqlparser::tokenizer::{Span, Location};
/// let spans = vec![
/// Span::new(Location::new(1, 1), Location::new(2, 5)),
/// Span::new(Location::new(2, 3), Location::new(3, 7)),
/// Span::new(Location::new(3, 1), Location::new(4, 2)),
/// ];
/// // line 1, column 1 -> line 4, column 2
/// assert_eq!(
/// Span::union_iter(spans),
/// Span::new(Location::new(1, 1), Location::new(4, 2))
/// );
pub fn union_iter<I: IntoIterator<Item = Span>>(iter: I) -> Option<Span> {
iter.into_iter().reduce(|acc, item| acc.union(&item))
}
}
/// A collection of [`Span`], meant to be used as a field of entities whose
/// location in the original SQL query is desired to be tracked. Sometimes an
/// entity can have multiple spans. e.g. if you want to track the position of
/// the column a that comes from SELECT 1 AS a UNION ALL SELECT 2 AS a you'll
/// need two spans.
#[derive(Debug, Clone)]
// Store the first [`Span`] on the stack because that is by far the most common
// case. More will spill onto the heap.
pub struct Spans(pub Vec<Span>);
impl Spans {
/// Creates a new empty [`Spans`] with no [`Span`].
pub fn new() -> Self {
Spans(Vec::new())
}
/// Returns the first [`Span`], if any. This is useful when you know that
/// there's gonna be only one [`Span`] at most.
pub fn first(&self) -> Option<Span> {
self.0.first().copied()
}
/// Returns a slice of the [`Span`]s.
pub fn get_spans(&self) -> &[Span] {
&self.0
}
/// Adds a [`Span`] to the collection.
pub fn add_span(&mut self, span: Span) {
self.0.push(span);
}
/// Iterates over the [`Span`]s.
pub fn iter(&self) -> impl Iterator<Item = &Span> {
self.0.iter()
}
}
impl Default for Spans {
fn default() -> Self {
Self::new()
}
}
// Since [`Spans`] will be used as a field in other structs, we don't want it to
// interfere with the equality and ordering of the entities themselves, since
// this is just diagnostics information for the end user.
impl PartialEq for Spans {
fn eq(&self, _other: &Self) -> bool {
true
}
}
// Since [`Spans`] will be used as a field in other structs, we don't want it to
// interfere with the equality and ordering of the entities themselves, since
// this is just diagnostics information for the end user.
impl Eq for Spans {}
// Since [`Spans`] will be used as a field in other structs, we don't want it to
// interfere with the equality and ordering of the entities themselves, since
// this is just diagnostics information for the end user.
impl PartialOrd for Spans {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
// Since [`Spans`] will be used as a field in other structs, we don't want it to
// interfere with the equality and ordering of the entities themselves, since
// this is just diagnostics information for the end user.
impl Ord for Spans {
fn cmp(&self, _other: &Self) -> Ordering {
Ordering::Equal
}
}
// Since [`Spans`] will be used as a field in other structs, we don't want it to
// interfere with the equality and ordering of the entities themselves, since
// this is just diagnostics information for the end user.
impl Hash for Spans {
fn hash<H: Hasher>(&self, _state: &mut H) {}
}