Skip to content

Commit 239c990

Browse files
Report source location on every parser error
1 parent 0cb62a1 commit 239c990

22 files changed

Lines changed: 919 additions & 726 deletions

‎Cargo.toml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ visitor = ["sqlparser_derive"]
5353
bigdecimal = { version = "0.4.1", features = ["serde"], optional = true }
5454
log = "0.4"
5555
recursive = { version = "0.1.1", optional = true}
56+
thiserror = { version = "2.0", default-features = false }
5657

5758
serde = { version = "1.0", default-features = false, features = ["derive", "alloc"], optional = true }
5859
# serde_json is only used in examples/cli, but we have to put it outside

‎src/ast/helpers/stmt_create_database.rs‎

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ use crate::ast::{
2828
CatalogSyncNamespaceMode, ContactEntry, ObjectName, Statement, StorageSerializationPolicy, Tag,
2929
};
3030
use crate::parser::ParserError;
31+
use crate::tokenizer::Span;
3132

3233
/// Builder for create database statement variant ([1]).
3334
///
@@ -357,9 +358,10 @@ impl TryFrom<Statement> for CreateDatabaseBuilder {
357358
with_tags,
358359
with_contacts,
359360
}),
360-
_ => Err(ParserError::ParserError(format!(
361-
"Expected create database statement, but received: {stmt}"
362-
))),
361+
_ => Err(ParserError::ParserError {
362+
message: format!("Expected create database statement, but received: {stmt}"),
363+
span: Span::empty(),
364+
}),
363365
}
364366
}
365367
}
@@ -369,6 +371,7 @@ mod tests {
369371
use crate::ast::helpers::stmt_create_database::CreateDatabaseBuilder;
370372
use crate::ast::{Ident, ObjectName, Statement};
371373
use crate::parser::ParserError;
374+
use crate::tokenizer::Span;
372375

373376
#[test]
374377
pub fn test_from_valid_statement() {
@@ -389,9 +392,10 @@ mod tests {
389392

390393
assert_eq!(
391394
CreateDatabaseBuilder::try_from(stmt).unwrap_err(),
392-
ParserError::ParserError(
393-
"Expected create database statement, but received: COMMIT".to_owned()
394-
)
395+
ParserError::ParserError {
396+
message: "Expected create database statement, but received: COMMIT".to_owned(),
397+
span: Span::empty(),
398+
}
395399
);
396400
}
397401
}

‎src/ast/helpers/stmt_create_table.rs‎

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ use crate::ast::{
3333
};
3434

3535
use crate::parser::ParserError;
36+
use crate::tokenizer::Span;
3637

3738
/// Builder for create table statement variant ([1]).
3839
///
@@ -677,9 +678,10 @@ impl TryFrom<Statement> for CreateTableBuilder {
677678
fn try_from(stmt: Statement) -> Result<Self, Self::Error> {
678679
match stmt {
679680
Statement::CreateTable(create_table) => Ok(create_table.into()),
680-
_ => Err(ParserError::ParserError(format!(
681-
"Expected create table statement, but received: {stmt}"
682-
))),
681+
_ => Err(ParserError::ParserError {
682+
message: format!("Expected create table statement, but received: {stmt}"),
683+
span: Span::empty(),
684+
}),
683685
}
684686
}
685687
}
@@ -769,6 +771,7 @@ mod tests {
769771
use crate::ast::helpers::stmt_create_table::CreateTableBuilder;
770772
use crate::ast::{Ident, ObjectName, Statement};
771773
use crate::parser::ParserError;
774+
use crate::tokenizer::Span;
772775

773776
#[test]
774777
pub fn test_from_valid_statement() {
@@ -790,9 +793,10 @@ mod tests {
790793

791794
assert_eq!(
792795
CreateTableBuilder::try_from(stmt).unwrap_err(),
793-
ParserError::ParserError(
794-
"Expected create table statement, but received: COMMIT".to_owned()
795-
)
796+
ParserError::ParserError {
797+
message: "Expected create table statement, but received: COMMIT".to_owned(),
798+
span: Span::empty(),
799+
}
796800
);
797801
}
798802
}

‎src/dialect/snowflake.rs‎

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ use crate::ast::{
3838
};
3939
use crate::dialect::{Dialect, Precedence};
4040
use crate::keywords::Keyword;
41-
use crate::parser::{IsOptional, Parser, ParserError};
41+
use crate::parser::{parser_err, IsOptional, Parser, ParserError};
4242
use crate::tokenizer::TokenWithSpan;
4343
use crate::tokenizer::{Span, Token};
4444
#[cfg(not(feature = "std"))]
@@ -435,7 +435,7 @@ impl Dialect for SnowflakeDialect {
435435
} else if parser.parse_keywords(&[Keyword::TAG]) {
436436
Ok(parse_column_tags(parser, with).map(|p| Some(ColumnOption::Tags(p))))
437437
} else {
438-
Err(ParserError::ParserError("not found match".to_string()))
438+
parser_err!("not found match", parser.peek_token_ref().span)
439439
}
440440
})
441441
}
@@ -742,9 +742,10 @@ fn parse_file_staging_command(kw: Keyword, parser: &mut Parser) -> Result<Statem
742742
Keyword::REMOVE | Keyword::RM => {
743743
Ok(Statement::Remove(FileStagingCommand { stage, pattern }))
744744
}
745-
_ => Err(ParserError::ParserError(
746-
"unexpected stage command, expecting LIST, LS, REMOVE or RM".to_string(),
747-
)),
745+
_ => parser_err!(
746+
"unexpected stage command, expecting LIST, LS, REMOVE or RM",
747+
parser.get_current_token().span
748+
),
748749
}
749750
}
750751

@@ -1092,9 +1093,10 @@ pub fn parse_create_table(
10921093
builder = builder.table_options(table_options);
10931094

10941095
if iceberg && builder.base_location.is_none() {
1095-
return Err(ParserError::ParserError(
1096-
"BASE_LOCATION is required for ICEBERG tables".to_string(),
1097-
));
1096+
return parser_err!(
1097+
"BASE_LOCATION is required for ICEBERG tables",
1098+
parser.peek_token_ref().span
1099+
);
10981100
}
10991101

11001102
Ok(builder.build())
@@ -1563,9 +1565,15 @@ fn parse_select_item_for_data_load(
15631565
let next_token = parser.next_token();
15641566
match next_token.token {
15651567
Token::Placeholder(w) => {
1566-
file_col_num = w.to_string().split_off(1).parse::<i32>().map_err(|e| {
1567-
ParserError::ParserError(format!("Could not parse '{w}' as i32: {e}"))
1568-
})?;
1568+
file_col_num = match w.to_string().split_off(1).parse::<i32>() {
1569+
Ok(n) => n,
1570+
Err(e) => {
1571+
return parser_err!(
1572+
format!("Could not parse '{w}' as i32: {e}"),
1573+
next_token.span
1574+
)
1575+
}
1576+
};
15691577
Ok(())
15701578
}
15711579
Token::Word(w) => {
@@ -1581,9 +1589,15 @@ fn parse_select_item_for_data_load(
15811589
let col_num_token = parser.next_token();
15821590
match col_num_token.token {
15831591
Token::Placeholder(w) => {
1584-
file_col_num = w.to_string().split_off(1).parse::<i32>().map_err(|e| {
1585-
ParserError::ParserError(format!("Could not parse '{w}' as i32: {e}"))
1586-
})?;
1592+
file_col_num = match w.to_string().split_off(1).parse::<i32>() {
1593+
Ok(n) => n,
1594+
Err(e) => {
1595+
return parser_err!(
1596+
format!("Could not parse '{w}' as i32: {e}"),
1597+
col_num_token.span
1598+
)
1599+
}
1600+
};
15871601
Ok(())
15881602
}
15891603
_ => parser.expected("file_col_num", col_num_token),
@@ -1730,9 +1744,7 @@ fn parse_session_options(
17301744
}
17311745
}
17321746
if options.is_empty() {
1733-
Err(ParserError::ParserError(
1734-
"expected at least one option".to_string(),
1735-
))
1747+
parser_err!("expected at least one option", parser.peek_token_ref().span)
17361748
} else {
17371749
Ok(options)
17381750
}

‎src/parser/alter.rs‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,10 @@ impl Parser<'_> {
3838
return self.parse_mssql_alter_role();
3939
}
4040

41-
Err(ParserError::ParserError(
42-
"ALTER ROLE is only support for PostgreSqlDialect, MsSqlDialect".into(),
43-
))
41+
parser_err!(
42+
"ALTER ROLE is only support for PostgreSqlDialect, MsSqlDialect",
43+
self.get_current_token().span
44+
)
4445
}
4546

4647
/// Parse ALTER POLICY statement

‎src/parser/merge.rs‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
//! SQL Parser for a `MERGE` statement
1414
1515
#[cfg(not(feature = "std"))]
16-
use alloc::{boxed::Box, format, vec, vec::Vec};
16+
use alloc::{boxed::Box, vec, vec::Vec};
1717

1818
use crate::{
1919
ast::{
@@ -124,7 +124,7 @@ impl Parser<'_> {
124124
) {
125125
return parser_err!(
126126
format_args!("UPDATE is not allowed in a {clause_kind} merge clause"),
127-
self.get_current_token().span.start
127+
self.get_current_token().span
128128
);
129129
}
130130

@@ -160,7 +160,7 @@ impl Parser<'_> {
160160
) {
161161
return parser_err!(
162162
format_args!("DELETE is not allowed in a {clause_kind} merge clause"),
163-
self.get_current_token().span.start
163+
self.get_current_token().span
164164
);
165165
};
166166

@@ -176,7 +176,7 @@ impl Parser<'_> {
176176
) {
177177
return parser_err!(
178178
format_args!("INSERT is not allowed in a {clause_kind} merge clause"),
179-
self.get_current_token().span.start
179+
self.get_current_token().span
180180
);
181181
};
182182

@@ -222,7 +222,7 @@ impl Parser<'_> {
222222
_ => {
223223
return parser_err!(
224224
"expected UPDATE, DELETE, INSERT or DO NOTHING in merge clause",
225-
self.peek_token_ref().span.start
225+
self.peek_token_ref().span
226226
);
227227
}
228228
};

0 commit comments

Comments
 (0)