Skip to content
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

Interval multiplication parses differently depending on operand order #1345

Closed
mcheshkov opened this issue Jul 18, 2024 · 8 comments
Closed

Comments

@mcheshkov
Copy link

Depending on operands order, intervals without leading fields (with literal alone) parses differently.

I've checked on sqlparser = "0.48.0"
SELECT 1 * interval '1 month'; parses as BinOp(Number, Interval(String)), which, I think, is correct:

projection: [
    UnnamedExpr(
        BinaryOp {
            left: Value(
                Number(
                    "1",
                    false,
                ),
            ),
            op: Multiply,
            right: Interval(
                Interval {
                    value: Value(
                        SingleQuotedString(
                            "1 month",
                        ),
                    ),
// ...
                },
            ),
        },
    ),
],

But SELECT interval '1 month' * 1; parses as Interval(BinOp(String, Number)), which, to me, is incorrect:

projection: [
    UnnamedExpr(
        Interval(
            Interval {
                value: BinaryOp {
                    left: Value(
                        SingleQuotedString(
                            "1 month",
                        ),
                    ),
                    op: Multiply,
                    right: Value(
                        Number(
                            "1",
                            false,
                        ),
                    ),
                },
// ...
            },
        ),
    ),
],

I think that culprit is these calls
https://github.com/sqlparser-rs/sqlparser-rs/blob/20f7ac59e38d52e293476b7ad844e7f744a16c43/src/parser/mod.rs#L2027
=>
https://github.com/sqlparser-rs/sqlparser-rs/blob/20f7ac59e38d52e293476b7ad844e7f744a16c43/src/parser/mod.rs#L906

It would consume not only literals, but any expression as well, and store result as Intervals value

I propose to change parse_interval_expr so it would allow only literals, or maybe even replace it with parse_value.
I didn't actually check if that would break any tests, but at first glance it should not.

Also representation of interval value in AST could be changed from Expr to Value, but that would break public API, so could be postponed.

Related:
#517
#705

@Abdullahsab3
Copy link

Abdullahsab3 commented Sep 5, 2024

I looked into this, since I think that's the root cause of apache/datafusion#12190 (Thanks @tshauck for the pointer). I think changing parse_interval_expr to parse_value would fix the issue of a wrongly parsed AST for the binops between intervals. However it would break the following syntax (and test):
SELECT INTERVAL 1 + 1 DAY

These PR might be relevant:

I think this syntax is used for the MySQL/BigQuery dialects.

@mcheshkov
Copy link
Author

Wow MySQL is strange powerful! It can parse INTERVAL CONCAT('1', '1') DAY, and interpret that an 11 day interval.

I guess it would need a separate flag in dialect then, something like "suports expressions in interval values", as PostgreSQL does not seem to support that.
Or even "parse literal value", because, I think, they both differ from standard, which requires both single-quoted strings and qualifier outside of string, while in PostgreSQL stuff like SELECT INTERVAL '''10:12 hours'''; works

@Abdullahsab3
Copy link

I guess it would need a separate flag in dialect then, something like "suports expressions in interval values", as PostgreSQL does not seem to support that.

I think that makes sense. I think a somewhat similar alternative is to define how binary operators between intervals are parsed. As an example:

Following is how you binop intervals in postgresql/Datafusion:

select interval '1' day + interval '2' day  --allowed
select interval '1 + 2' day --not allowed

Following is how you binop intervals in mysql

select interval 1 + 1 day  --allowed
select interval 1 day + interval 1 day --not allowed

There might be other approaches/syntax for binary operations between intervals. Not sure

@Abdullahsab3
Copy link

I take it back. I think postgres does kinda support that, just not in the same way

select interval '1 month + 2 day' day

However, it shouldn't matter actually for sqlparser, since it will just be Interval { value: Value(SingleQuotedString("1 month + 2 day")), leading_field: Some(Day)

@Abdullahsab3
Copy link

Following PR that has been recently merged might be relevant:

#1398

@findepi
Copy link
Member

findepi commented Sep 12, 2024

cc @alamb

@alamb
Copy link
Contributor

alamb commented Sep 13, 2024

@samuelcolvin has also made some good progress on cleaning up interval parsing recently. Perhaps you can retry the example with the recently release sqlparser 0.51.0

@mcheshkov
Copy link
Author

Yes, I've rechecked, and my examples parses fine on sqlparser = "0.51.0", so I'll just close this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants