Skip to content

Commit dccebcb

Browse files
committed
locations: collect locations of expressions and SelectItems
1 parent 0842efe commit dccebcb

16 files changed

+294
-235
lines changed

src/ast/mod.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,10 @@ where
346346
pub fn unwrap(self) -> T {
347347
self.inner
348348
}
349+
350+
pub fn span_location(&self) -> Span {
351+
self.span
352+
}
349353
}
350354

351355
pub trait SpanWrapped: Clone + Eq + Ord + std::hash::Hash + PartialOrd + PartialEq {
@@ -1272,7 +1276,7 @@ pub enum Statement {
12721276
table: bool,
12731277
on: Option<OnInsert>,
12741278
/// RETURNING
1275-
returning: Option<Vec<SelectItem>>,
1279+
returning: Option<Vec<WithSpan<SelectItem>>>,
12761280
},
12771281
// TODO: Support ROW FORMAT
12781282
Directory {
@@ -1332,7 +1336,7 @@ pub enum Statement {
13321336
/// WHERE
13331337
selection: Option<Expr>,
13341338
/// RETURNING
1335-
returning: Option<Vec<SelectItem>>,
1339+
returning: Option<Vec<WithSpan<SelectItem>>>,
13361340
},
13371341
/// DELETE
13381342
Delete {
@@ -1345,7 +1349,7 @@ pub enum Statement {
13451349
/// WHERE
13461350
selection: Option<Expr>,
13471351
/// RETURNING
1348-
returning: Option<Vec<SelectItem>>,
1352+
returning: Option<Vec<WithSpan<SelectItem>>>,
13491353
},
13501354
/// CREATE VIEW
13511355
CreateView {

src/ast/query.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ pub struct Select {
204204
/// MSSQL syntax: `TOP (<N>) [ PERCENT ] [ WITH TIES ]`
205205
pub top: Option<Top>,
206206
/// projection expressions
207-
pub projection: Vec<SelectItem>,
207+
pub projection: Vec<WithSpan<SelectItem>>,
208208
/// INTO
209209
pub into: Option<SelectInto>,
210210
/// FROM
@@ -298,7 +298,7 @@ pub struct LateralView {
298298
/// LATERAL VIEW table name
299299
pub lateral_view_name: ObjectName,
300300
/// LATERAL VIEW optional column aliases
301-
pub lateral_col_alias: Vec<Ident>,
301+
pub lateral_col_alias: Vec<WithSpan<Ident>>,
302302
/// LATERAL VIEW OUTER
303303
pub outer: bool,
304304
}
@@ -382,9 +382,9 @@ impl fmt::Display for Cte {
382382
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
383383
pub enum SelectItem {
384384
/// Any expression, not followed by `[ AS ] alias`
385-
UnnamedExpr(Expr),
385+
UnnamedExpr(WithSpan<Expr>),
386386
/// An expression, followed by `[ AS ] alias`
387-
ExprWithAlias { expr: Expr, alias: Ident },
387+
ExprWithAlias { expr: WithSpan<Expr>, alias: WithSpan<Ident> },
388388
/// `alias.*` or even `schema.table.*`
389389
QualifiedWildcard(ObjectName, WildcardAdditionalOptions),
390390
/// An unqualified `*`
@@ -697,7 +697,7 @@ pub enum TableFactor {
697697
alias: Option<TableAlias>,
698698
array_expr: Box<Expr>,
699699
with_offset: bool,
700-
with_offset_alias: Option<Ident>,
700+
with_offset_alias: Option<WithSpan<Ident>>,
701701
},
702702
/// Represents a parenthesized table factor. The SQL spec only allows a
703703
/// join expression (`(foo <JOIN> bar [ <JOIN> baz ... ])`) to be nested,
@@ -857,7 +857,7 @@ impl fmt::Display for TableFactor {
857857
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
858858
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
859859
pub struct TableAlias {
860-
pub name: Ident,
860+
pub name: WithSpan<Ident>,
861861
pub columns: Vec<Ident>,
862862
}
863863

src/parser.rs

Lines changed: 68 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ impl fmt::Display for ParserError {
192192
impl std::error::Error for ParserError {}
193193

194194
// By default, allow expressions up to this deep before erroring
195-
const DEFAULT_REMAINING_DEPTH: usize = 50;
195+
const DEFAULT_REMAINING_DEPTH: usize = 48;
196196

197197
#[derive(Debug, Default, Clone, PartialEq, Eq)]
198198
pub struct ParserOptions {
@@ -2291,7 +2291,7 @@ impl<'a> Parser<'a> {
22912291
}
22922292

22932293
/// Parse a comma-separated list of 1+ SelectItem
2294-
pub fn parse_projection(&mut self) -> Result<Vec<SelectItem>, ParserError> {
2294+
pub fn parse_projection(&mut self) -> Result<Vec<WithSpan<SelectItem>>, ParserError> {
22952295
// BigQuery allows trailing commas, but only in project lists
22962296
// e.g. `SELECT 1, 2, FROM t`
22972297
// https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#trailing_commas
@@ -4728,7 +4728,7 @@ impl<'a> Parser<'a> {
47284728
pub fn parse_optional_alias(
47294729
&mut self,
47304730
reserved_kwds: &[Keyword],
4731-
) -> Result<Option<Ident>, ParserError> {
4731+
) -> Result<Option<WithSpan<Ident>>, ParserError> {
47324732
let after_as = self.parse_keyword(Keyword::AS);
47334733
let next_token = self.next_token();
47344734
match next_token.token {
@@ -4738,7 +4738,7 @@ impl<'a> Parser<'a> {
47384738
// (For example, in `FROM t1 JOIN` the `JOIN` will always be parsed as a keyword,
47394739
// not an alias.)
47404740
Token::Word(w) if after_as || !reserved_kwds.contains(&w.keyword) => {
4741-
Ok(Some(w.to_ident()))
4741+
Ok(Some(w.to_ident().spanning(next_token.span)))
47424742
}
47434743
// MSSQL supports single-quoted strings as aliases for columns
47444744
// We accept them as table aliases too, although MSSQL does not.
@@ -4752,9 +4752,9 @@ impl<'a> Parser<'a> {
47524752
// character. When it sees such a <literal>, your DBMS will
47534753
// ignore the <separator> and treat the multiple strings as
47544754
// a single <literal>."
4755-
Token::SingleQuotedString(s) => Ok(Some(Ident::with_quote('\'', s))),
4755+
Token::SingleQuotedString(s) => Ok(Some(Ident::with_quote('\'', s).spanning(next_token.span))),
47564756
// Support for MySql dialect double quoted string, `AS "HOUR"` for example
4757-
Token::DoubleQuotedString(s) => Ok(Some(Ident::with_quote('\"', s))),
4757+
Token::DoubleQuotedString(s) => Ok(Some(Ident::with_quote('\"', s).spanning(next_token.span))),
47584758
_ => {
47594759
if after_as {
47604760
return self.expected("an identifier after AS", next_token);
@@ -5273,7 +5273,7 @@ impl<'a> Parser<'a> {
52735273

52745274
/// Parse a CTE (`alias [( col1, col2, ... )] AS (subquery)`)
52755275
pub fn parse_cte(&mut self) -> Result<Cte, ParserError> {
5276-
let name = self.parse_identifier()?.unwrap();
5276+
let name = self.parse_identifier()?;
52775277

52785278
let mut cte = if self.parse_keyword(Keyword::AS) {
52795279
self.expect_token(&Token::LParen)?;
@@ -5444,7 +5444,7 @@ impl<'a> Parser<'a> {
54445444
let outer = self.parse_keyword(Keyword::OUTER);
54455445
let lateral_view = self.parse_expr()?;
54465446
let lateral_view_name = self.parse_object_name()?;
5447-
let lateral_col_alias = self
5447+
let lateral_col_alias: Vec<WithSpan<Ident>> = self
54485448
.parse_comma_separated(|parser| {
54495449
parser.parse_optional_alias(&[
54505450
Keyword::WHERE,
@@ -6582,7 +6582,8 @@ impl<'a> Parser<'a> {
65826582
}
65836583

65846584
/// Parse a comma-delimited list of projections after SELECT
6585-
pub fn parse_select_item(&mut self) -> Result<SelectItem, ParserError> {
6585+
pub fn parse_select_item(&mut self) -> Result<WithSpan<SelectItem>, ParserError> {
6586+
let start_span = self.index;
65866587
match self.parse_wildcard_expr()? {
65876588
WildcardExpr::Expr(expr) => {
65886589
let expr: Expr = if self.dialect.supports_filter_during_aggregation()
@@ -6603,19 +6604,29 @@ impl<'a> Parser<'a> {
66036604
} else {
66046605
expr
66056606
};
6607+
let expr_with_location = expr.spanning(self.span_from_index(start_span));
66066608
self.parse_optional_alias(keywords::RESERVED_FOR_COLUMN_ALIAS)
66076609
.map(|alias| match alias {
6608-
Some(alias) => SelectItem::ExprWithAlias { expr, alias },
6609-
None => SelectItem::UnnamedExpr(expr),
6610+
Some(alias) => SelectItem::ExprWithAlias {
6611+
expr: expr_with_location,
6612+
alias,
6613+
}
6614+
.spanning(self.span_from_index(start_span)),
6615+
None => {
6616+
SelectItem::UnnamedExpr(expr_with_location)
6617+
.spanning(self.span_from_index(start_span))
6618+
}
66106619
})
66116620
}
66126621
WildcardExpr::QualifiedWildcard(prefix) => Ok(SelectItem::QualifiedWildcard(
66136622
prefix,
66146623
self.parse_wildcard_additional_options()?,
6615-
)),
6624+
)
6625+
.spanning(self.span_from_index(start_span))),
66166626
WildcardExpr::Wildcard => Ok(SelectItem::Wildcard(
66176627
self.parse_wildcard_additional_options()?,
6618-
)),
6628+
)
6629+
.spanning(self.span_from_index(start_span))),
66196630
}
66206631
}
66216632

@@ -7293,6 +7304,50 @@ impl<'a> Parser<'a> {
72937304
representation: UserDefinedTypeRepresentation::Composite { attributes },
72947305
})
72957306
}
7307+
7308+
fn span_from_index(&mut self, mut start_index: usize) -> Span {
7309+
let mut start_token = &self.tokens[start_index];
7310+
loop {
7311+
match start_token {
7312+
TokenWithLocation {
7313+
token: Token::Whitespace(_),
7314+
span: _,
7315+
} => {
7316+
start_index += 1;
7317+
start_token = &self.tokens[start_index];
7318+
continue;
7319+
}
7320+
_ => break,
7321+
}
7322+
}
7323+
let start_span = start_token.span;
7324+
7325+
let mut idx = self.index.max(start_index).min(self.tokens.len());
7326+
loop {
7327+
if idx <= start_index || idx >= self.tokens.len() {
7328+
break;
7329+
}
7330+
let curr_token = &self.tokens[idx];
7331+
match curr_token {
7332+
TokenWithLocation {
7333+
token: Token::Whitespace(_),
7334+
span: _,
7335+
} => {
7336+
idx -= 1;
7337+
continue;
7338+
}
7339+
TokenWithLocation {
7340+
token: Token::Word(word),
7341+
span: _,
7342+
} if word.keyword != Keyword::NoKeyword => {
7343+
idx -= 1;
7344+
continue;
7345+
}
7346+
non_whitespace => return non_whitespace.span.union(start_span),
7347+
}
7348+
}
7349+
return start_span;
7350+
}
72967351
}
72977352

72987353
impl Word {

src/test_utils.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ pub fn number(n: &'static str) -> Value {
207207

208208
pub fn table_alias(name: impl Into<String>) -> Option<TableAlias> {
209209
Some(TableAlias {
210-
name: Ident::new(name),
210+
name: Ident::new(name).empty_span(),
211211
columns: vec![],
212212
})
213213
}

src/tokenizer.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,7 @@ pub struct Location {
358358
}
359359

360360
impl Location {
361-
fn is_valid(&self) -> bool {
361+
pub fn is_valid(&self) -> bool {
362362
self.line > 0 && self.column > 0
363363
}
364364
}

tests/sqlparser_bigquery.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ fn test_select_wildcard_with_except() {
337337
additional_elements: vec![],
338338
}),
339339
..Default::default()
340-
});
340+
}).empty_span();
341341
assert_eq!(expected, select.projection[0]);
342342

343343
let select = bigquery_and_generic()
@@ -348,7 +348,7 @@ fn test_select_wildcard_with_except() {
348348
additional_elements: vec![Ident::new("employee_id")],
349349
}),
350350
..Default::default()
351-
});
351+
}).empty_span();
352352
assert_eq!(expected, select.projection[0]);
353353

354354
assert_eq!(
@@ -382,7 +382,7 @@ fn test_select_wildcard_with_replace() {
382382
})],
383383
}),
384384
..Default::default()
385-
});
385+
}).empty_span();
386386
assert_eq!(expected, select.projection[0]);
387387

388388
let select = bigquery_and_generic().verified_only_select(
@@ -417,7 +417,7 @@ fn test_select_wildcard_with_replace() {
417417
],
418418
}),
419419
..Default::default()
420-
});
420+
}).empty_span();
421421
assert_eq!(expected, select.projection[0]);
422422
}
423423

@@ -461,7 +461,7 @@ fn parse_map_access_offset() {
461461
order_by: vec![],
462462
null_treatment: None,
463463
})],
464-
})
464+
}.empty_span()).empty_span()
465465
);
466466

467467
// test other operators

tests/sqlparser_clickhouse.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ fn parse_array_access_expr() {
5959
order_by: vec![],
6060
null_treatment: None,
6161
})],
62-
})],
62+
}.empty_span()).empty_span()],
6363
into: None,
6464
from: vec![TableWithJoins {
6565
relation: Table {
@@ -182,7 +182,7 @@ fn parse_delimited_identifiers() {
182182
with_hints,
183183
} => {
184184
assert_eq!(vec![Ident::with_quote('"', "a table")], name.0);
185-
assert_eq!(Ident::with_quote('"', "alias"), alias.unwrap().name);
185+
assert_eq!(Ident::with_quote('"', "alias").empty_span(), alias.unwrap().name);
186186
assert!(args.is_none());
187187
assert!(with_hints.is_empty());
188188
}
@@ -209,13 +209,13 @@ fn parse_delimited_identifiers() {
209209
}),
210210
expr_from_projection(&select.projection[1]),
211211
);
212-
match &select.projection[2] {
212+
match select.projection[2].clone().unwrap() {
213213
SelectItem::ExprWithAlias { expr, alias } => {
214214
assert_eq!(
215-
&Expr::Identifier(Ident::with_quote('"', "simple id").empty_span()),
215+
Expr::Identifier(Ident::with_quote('"', "simple id").empty_span()).empty_span(),
216216
expr
217217
);
218-
assert_eq!(&Ident::with_quote('"', "column alias"), alias);
218+
assert_eq!(Ident::with_quote('"', "column alias").empty_span(), alias);
219219
}
220220
_ => panic!("Expected ExprWithAlias"),
221221
}

0 commit comments

Comments
 (0)