Skip to content

Commit fc8e44a

Browse files
committed
locations: collect locations of expressions and SelectItems
1 parent fba2a14 commit fc8e44a

17 files changed

+337
-163
lines changed

src/ast/dml.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -489,7 +489,7 @@ pub struct Insert {
489489
pub table: bool,
490490
pub on: Option<OnInsert>,
491491
/// RETURNING
492-
pub returning: Option<Vec<SelectItem>>,
492+
pub returning: Option<Vec<WithSpan<SelectItem>>>,
493493
/// Only for mysql
494494
pub replace_into: bool,
495495
/// Only for mysql
@@ -587,7 +587,7 @@ pub struct Delete {
587587
/// WHERE
588588
pub selection: Option<Expr>,
589589
/// RETURNING
590-
pub returning: Option<Vec<SelectItem>>,
590+
pub returning: Option<Vec<WithSpan<SelectItem>>>,
591591
/// ORDER BY (MySQL)
592592
pub order_by: Vec<OrderByExpr>,
593593
/// LIMIT (MySQL)

src/ast/mod.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,10 @@ where
551551
pub fn unwrap(self) -> T {
552552
self.inner
553553
}
554+
555+
pub fn span_location(&self) -> Span {
556+
self.span
557+
}
554558
}
555559

556560
pub trait SpanWrapped: Clone + Eq + Ord + std::hash::Hash + PartialOrd + PartialEq {
@@ -2442,7 +2446,7 @@ pub enum Statement {
24422446
/// WHERE
24432447
selection: Option<Expr>,
24442448
/// RETURNING
2445-
returning: Option<Vec<SelectItem>>,
2449+
returning: Option<Vec<WithSpan<SelectItem>>>,
24462450
},
24472451
/// ```sql
24482452
/// DELETE

src/ast/query.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ impl fmt::Display for Query {
112112
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
113113
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
114114
pub struct ProjectionSelect {
115-
pub projection: Vec<SelectItem>,
115+
pub projection: Vec<WithSpan<SelectItem>>,
116116
pub order_by: Option<OrderBy>,
117117
pub group_by: Option<GroupByExpr>,
118118
}
@@ -280,7 +280,7 @@ pub struct Select {
280280
/// MSSQL syntax: `TOP (<N>) [ PERCENT ] [ WITH TIES ]`
281281
pub top: Option<Top>,
282282
/// projection expressions
283-
pub projection: Vec<SelectItem>,
283+
pub projection: Vec<WithSpan<SelectItem>>,
284284
/// INTO
285285
pub into: Option<SelectInto>,
286286
/// FROM

src/parser/mod.rs

+69-11
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ impl fmt::Display for ParserError {
183183
impl std::error::Error for ParserError {}
184184

185185
// By default, allow expressions up to this deep before erroring
186-
const DEFAULT_REMAINING_DEPTH: usize = 50;
186+
const DEFAULT_REMAINING_DEPTH: usize = 48;
187187

188188
/// Composite types declarations using angle brackets syntax can be arbitrary
189189
/// nested such that the following declaration is possible:
@@ -3400,7 +3400,7 @@ impl<'a> Parser<'a> {
34003400
}
34013401

34023402
/// Parse a comma-separated list of 1+ SelectItem
3403-
pub fn parse_projection(&mut self) -> Result<Vec<SelectItem>, ParserError> {
3403+
pub fn parse_projection(&mut self) -> Result<Vec<WithSpan<SelectItem>>, ParserError> {
34043404
// BigQuery and Snowflake allow trailing commas, but only in project lists
34053405
// e.g. `SELECT 1, 2, FROM t`
34063406
// https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#trailing_commas
@@ -8287,7 +8287,7 @@ impl<'a> Parser<'a> {
82878287
/// use sqlparser::parser::Parser;
82888288
///
82898289
/// let dialect = GenericDialect {};
8290-
/// let expected = vec![Ident::new("one"), Ident::new("two")];
8290+
/// let expected = vec![Ident::new("one").empty_span(), Ident::new("two").empty_span()];
82918291
///
82928292
/// // expected usage
82938293
/// let sql = "one.two";
@@ -11209,15 +11209,18 @@ impl<'a> Parser<'a> {
1120911209
}
1121011210

1121111211
/// Parse a comma-delimited list of projections after SELECT
11212-
pub fn parse_select_item(&mut self) -> Result<SelectItem, ParserError> {
11212+
pub fn parse_select_item(&mut self) -> Result<WithSpan<SelectItem>, ParserError> {
11213+
let start_span = self.index;
1121311214
match self.parse_wildcard_expr()? {
1121411215
Expr::QualifiedWildcard(prefix) => Ok(SelectItem::QualifiedWildcard(
1121511216
prefix,
1121611217
self.parse_wildcard_additional_options()?,
11217-
)),
11218-
Expr::Wildcard => Ok(SelectItem::Wildcard(
11219-
self.parse_wildcard_additional_options()?,
11220-
)),
11218+
)
11219+
.spanning(self.span_from_index(start_span))),
11220+
Expr::Wildcard => Ok(
11221+
SelectItem::Wildcard(self.parse_wildcard_additional_options()?)
11222+
.spanning(self.span_from_index(start_span)),
11223+
),
1122111224
Expr::Identifier(v) if v.value.to_lowercase() == "from" && v.quote_style.is_none() => {
1122211225
parser_err!(
1122311226
format!("Expected an expression, found: {}", v),
@@ -11240,13 +11243,17 @@ impl<'a> Parser<'a> {
1124011243
Ok(SelectItem::ExprWithAlias {
1124111244
expr: *right,
1124211245
alias,
11243-
})
11246+
}
11247+
.spanning(self.span_from_index(start_span)))
1124411248
}
1124511249
expr => self
1124611250
.parse_optional_alias(keywords::RESERVED_FOR_COLUMN_ALIAS)
1124711251
.map(|alias| match alias {
11248-
Some(alias) => SelectItem::ExprWithAlias { expr, alias },
11249-
None => SelectItem::UnnamedExpr(expr),
11252+
Some(alias) => SelectItem::ExprWithAlias { expr, alias }
11253+
.spanning(self.span_from_index(start_span)),
11254+
None => {
11255+
SelectItem::UnnamedExpr(expr).spanning(self.span_from_index(start_span))
11256+
}
1125011257
}),
1125111258
}
1125211259
}
@@ -12249,6 +12256,57 @@ impl<'a> Parser<'a> {
1224912256
self.tokens
1225012257
}
1225112258

12259+
fn span_from_index(&mut self, mut start_index: usize) -> Span {
12260+
let mut start_token = &self.tokens[start_index];
12261+
loop {
12262+
match start_token {
12263+
TokenWithLocation {
12264+
token: Token::Whitespace(_),
12265+
span: _,
12266+
} => {
12267+
start_index += 1;
12268+
start_token = &self.tokens[start_index];
12269+
continue;
12270+
}
12271+
_ => break,
12272+
}
12273+
}
12274+
let start_span = start_token.span;
12275+
12276+
let mut idx = self.index.max(start_index).min(self.tokens.len() - 1);
12277+
loop {
12278+
if idx <= start_index || idx >= self.tokens.len() {
12279+
break;
12280+
}
12281+
let curr_token = &self.tokens[idx];
12282+
match curr_token {
12283+
TokenWithLocation {
12284+
token: Token::Whitespace(_),
12285+
span: _,
12286+
} => {
12287+
idx -= 1;
12288+
continue;
12289+
}
12290+
TokenWithLocation {
12291+
token: Token::Comma,
12292+
span: _,
12293+
} => {
12294+
idx -= 1;
12295+
continue;
12296+
}
12297+
TokenWithLocation {
12298+
token: Token::Word(word),
12299+
span: _,
12300+
} if word.keyword != Keyword::NoKeyword => {
12301+
idx -= 1;
12302+
continue;
12303+
}
12304+
non_whitespace => return non_whitespace.span.union(start_span),
12305+
}
12306+
}
12307+
start_span
12308+
}
12309+
1225212310
/// Returns true if the next keyword indicates a sub query, i.e. SELECT or WITH
1225312311
fn peek_sub_query(&mut self) -> bool {
1225412312
if self

src/tokenizer.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -439,7 +439,7 @@ pub struct Location {
439439
}
440440

441441
impl Location {
442-
fn is_valid(&self) -> bool {
442+
pub fn is_valid(&self) -> bool {
443443
self.line > 0 && self.column > 0
444444
}
445445
pub fn of(line: LineNumber, column: ColumnPosition) -> Self {

tests/sqlparser_bigquery.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1580,6 +1580,7 @@ fn parse_hyphenated_table_identifiers() {
15801580
Ident::new("x").empty_span(),
15811581
]))
15821582
})
1583+
.empty_span()
15831584
);
15841585

15851586
let error_sql = "select foo-bar.* from foo-bar";

tests/sqlparser_clickhouse.rs

+12-10
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ fn parse_map_access_expr() {
5858
),
5959
syntax: MapAccessSyntax::Bracket
6060
}],
61-
})],
61+
})
62+
.empty_span()],
6263
into: None,
6364
from: vec![TableWithJoins {
6465
relation: Table {
@@ -211,7 +212,7 @@ fn parse_delimited_identifiers() {
211212
}),
212213
expr_from_projection(&select.projection[1]),
213214
);
214-
match &select.projection[2] {
215+
match &select.projection[2].clone().unwrap() {
215216
SelectItem::ExprWithAlias { expr, alias } => {
216217
assert_eq!(
217218
&Expr::Identifier(Ident::with_quote('"', "simple id").empty_span()),
@@ -319,8 +320,8 @@ fn parse_alter_table_add_projection() {
319320
name: Ident::new("my_name").empty_span(),
320321
select: ProjectionSelect {
321322
projection: vec![
322-
UnnamedExpr(Identifier(Ident::new("a").empty_span())),
323-
UnnamedExpr(Identifier(Ident::new("b").empty_span())),
323+
UnnamedExpr(Identifier(Ident::new("a").empty_span())).empty_span(),
324+
UnnamedExpr(Identifier(Ident::new("b").empty_span())).empty_span(),
324325
],
325326
group_by: Some(GroupByExpr::Expressions(
326327
vec![Identifier(Ident::new("a").empty_span())],
@@ -1006,9 +1007,10 @@ fn parse_select_star_except() {
10061007
fn parse_select_parametric_function() {
10071008
match clickhouse_and_generic().verified_stmt("SELECT HISTOGRAM(0.5, 0.6)(x, y) FROM t") {
10081009
Statement::Query(query) => {
1009-
let projection: &Vec<SelectItem> = query.body.as_select().unwrap().projection.as_ref();
1010+
let projection: &Vec<WithSpan<SelectItem>> =
1011+
query.body.as_select().unwrap().projection.as_ref();
10101012
assert_eq!(projection.len(), 1);
1011-
match &projection[0] {
1013+
match projection[0].clone().unwrap() {
10121014
UnnamedExpr(Expr::Function(f)) => {
10131015
let args = match &f.args {
10141016
FunctionArguments::List(ref args) => args,
@@ -1433,10 +1435,10 @@ fn parse_create_table_on_commit_and_as_query() {
14331435
assert_eq!(on_commit, Some(OnCommit::PreserveRows));
14341436
assert_eq!(
14351437
query.unwrap().body.as_select().unwrap().projection,
1436-
vec![UnnamedExpr(Expr::Value(Value::Number(
1437-
"1".parse().unwrap(),
1438-
false
1439-
)))]
1438+
vec![
1439+
UnnamedExpr(Expr::Value(Value::Number("1".parse().unwrap(), false)))
1440+
.empty_span()
1441+
]
14401442
);
14411443
}
14421444
_ => unreachable!(),

0 commit comments

Comments
 (0)