Skip to content

Attach Diagnostic to syntax errors #15680

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Apr 16, 2025

Conversation

logan-keede
Copy link
Contributor

@logan-keede logan-keede commented Apr 10, 2025

Which issue does this PR close?

Rationale for this change

converting ParserError into DataFusionError to attach diagnostic through expected.

What changes are included in this PR?

Are these changes tested?

Are there any user-facing changes?

@github-actions github-actions bot added the sql SQL Planner label Apr 10, 2025
@logan-keede logan-keede marked this pull request as ready for review April 13, 2025 18:01
@logan-keede
Copy link
Contributor Author

cc @eliaperantoni

@logan-keede logan-keede changed the title WIP: Attach Diagnostic to syntax errors Attach Diagnostic to syntax errors Apr 13, 2025
Copy link
Contributor

@alamb alamb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @logan-keede !

Is it possible to add a test for this feature, perhaps in

fn test_qualified_column_not_found() -> Result<()> {
let query = "SELECT /*a*/person.first_namex/*a*/ FROM person";
let spans = get_spans(query);
let diag = do_query(query);
assert_snapshot!(diag.message, @"column 'first_namex' not found in 'person'");
assert_eq!(diag.span, Some(spans["a"]));
Ok(())
}
?

@logan-keede
Copy link
Contributor Author

Thank you @logan-keede !

Is it possible to add a test for this feature, perhaps in

fn test_qualified_column_not_found() -> Result<()> {
let query = "SELECT /*a*/person.first_namex/*a*/ FROM person";
let spans = get_spans(query);
let diag = do_query(query);
assert_snapshot!(diag.message, @"column 'first_namex' not found in 'person'");
assert_eq!(diag.span, Some(spans["a"]));
Ok(())
}

?

Yes, I will do that. Thanks for the review!!

let statement = Parser::new(&dialect)
.try_with_sql(sql)
// let dialect = GenericDialect {};
let statement = DFParserBuilder::new(sql)
Copy link
Contributor Author

@logan-keede logan-keede Apr 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is somewhat out of the way, but I think using DFParser makes more sense here, as that's what is ultimately expected to be used by user.

Copy link
Contributor

@alamb alamb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @logan-keede -- this looks great (as always).

Since DFParser is a public API this is technically a breaking change, so I will mark the PR as such

I also tested this in datafusion-cli locally and it works great:

DataFusion CLI v46.0.1
> select
;  🤔 Invalid statement: SQL error: ParserError("Expected: an expression, found: ; at Line: 1, Column: 7")

// Convert TokenizerError -> ParserError
let tokens = tokenizer
.tokenize_with_location()
.map_err(|e| ParserError::TokenizerError(e.to_string()))?;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is weird that TokenizerError is different than ParserError::TokenizerErrir and that this is the right way to convert between them. Nothing to change in this PR, maybe something to make nicer . Ideally I would love to see something like:

            .map_err(ParserError::From)

found.span.start
))
.map_err(|e| {
let e: DataFusionError = e.into();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here is an alternate syntax that I find more explicit, but totally uneeded

Suggested change
let e: DataFusionError = e.into();
let e = DataFusionError::from(e);

return Err(ParserError::ParserError(
"Missing TO clause in COPY statement".into(),
));
return parser_err!(format!("Missing TO clause in COPY statement"))?;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice cleanups

return Err(ParserError::ParserError(format!(
"Unexpected token {token}"
)));
return parser_err!(format!("Unexpected token {token}"))?;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The parser_err macro already handles the string interpolation so you can do this insted:

Suggested change
return parser_err!(format!("Unexpected token {token}"))?;
return parser_err!("Unexpected token {token}")?;

(There are a few other examples of this below)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can probably use expected function here. I will try to commit that and other
suggestions tomorrow. (It's quite late here)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No rush -- I think we are going to hold of merging any more code changes until we make a 47.0.0 release branch / candidate.

@alamb alamb added the api change Changes the API exposed to users of the crate label Apr 15, 2025
@github-actions github-actions bot added the sqllogictest SQL Logic Tests (.slt) label Apr 16, 2025
Copy link
Contributor

@alamb alamb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

parser_err!(format!("Expected {expected}, found: {found}"))
) -> Result<T, DataFusionError> {
let sql_parser_span = found.span;
parser_err!(format!(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this actually gives me an idea that err! should support diagnostics as optional param, so we can remove extra map_err

@comphead comphead merged commit 42a45d1 into apache:main Apr 16, 2025
27 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api change Changes the API exposed to users of the crate sql SQL Planner sqllogictest SQL Logic Tests (.slt)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Attach Diagnostic to syntax errors
3 participants