Skip to content

Commit

Permalink
sqlparser: Improve interval parsing (#13165)
Browse files Browse the repository at this point in the history
* sqlparser: Improve interval parsing

Parse only strict valid units for intervals. We should not allow any
arbitrary string value here. We already had the internal enumerable
available, but we were not using yet.

Signed-off-by: Dirkjan Bussink <d.bussink@gmail.com>

* sqlparser: Explicit parsing for date functions with intervals

In order to better be able to implement these in the evalengine, it's
easier to parse them explicitly in the parser. This ensures we have the
interval type etc. directly available instead of having to infer it
from a separate expression.

Also makes parsing these functions more strict and better match MySQL.

Signed-off-by: Dirkjan Bussink <d.bussink@gmail.com>

* sqlparser: Remove INTERVAL as general expression

INTERVAL is not a possible general expression, but only used in specific
cases. With the previous change, we already have it all handled for date
functions. The only remaining cases are for + and - where this is
handled.

Those cases are a bit special. You can have an interval on both sides of
a +, but for a - it can only be done on the right hand side.

Signed-off-by: Dirkjan Bussink <d.bussink@gmail.com>

---------

Signed-off-by: Dirkjan Bussink <d.bussink@gmail.com>
  • Loading branch information
dbussink authored May 29, 2023
1 parent 3307b85 commit 2ba1edc
Show file tree
Hide file tree
Showing 19 changed files with 8,874 additions and 8,164 deletions.
4 changes: 2 additions & 2 deletions go/test/endtoend/vtgate/queries/misc/misc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,8 +174,8 @@ func TestIntervalWithMathFunctions(t *testing.T) {
// Set the time zone explicitly to UTC, otherwise the output of FROM_UNIXTIME is going to be dependent
// on the time zone of the system.
mcmp.Exec("SET time_zone = '+00:00'")
mcmp.AssertMatches("select '2020-01-01' + interval month(DATE_SUB(FROM_UNIXTIME(1234), interval 1 month))-1 month", `[[CHAR("2020-12-01")]]`)
mcmp.AssertMatches("select DATE_ADD(MIN(FROM_UNIXTIME(1673444922)),interval -DAYOFWEEK(MIN(FROM_UNIXTIME(1673444922)))+1 DAY)", `[[DATETIME("2023-01-08 13:48:42")]]`)
mcmp.AssertMatches("select '2020-01-01' + interval month(date_sub(FROM_UNIXTIME(1234), interval 1 month))-1 month", `[[CHAR("2020-12-01")]]`)
mcmp.AssertMatches("select date_add(MIN(FROM_UNIXTIME(1673444922)),interval -DAYOFWEEK(MIN(FROM_UNIXTIME(1673444922)))+1 DAY)", `[[DATETIME("2023-01-08 13:48:42")]]`)
}

// TestCast tests the queries that contain the cast function.
Expand Down
50 changes: 39 additions & 11 deletions go/vt/sqlparser/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -2154,6 +2154,7 @@ type (
// More information available here: https://dev.mysql.com/doc/refman/8.0/en/window-functions-frames.html
FramePoint struct {
Type FramePointType
Unit IntervalTypes
Expr Expr
}

Expand Down Expand Up @@ -2194,6 +2195,16 @@ type (
FromFirstLastType int8
)

// DateAddExprType is an enum to get types of DateAddExpr.
// This can be one of ADDDATE, DATE_ADD or a '+' operator
// with an interval left or right.
type DateAddExprType int8

// DateSubExprType is an enum to get types of DateAddExpr.
// This can be one of SUBDATE, DATE_SUB or a '-' operator
// with an interval right.
type DateSubExprType int8

// *********** Expressions
type (
// Expr represents an expression.
Expand Down Expand Up @@ -2340,12 +2351,6 @@ type (
Expr Expr
}

// IntervalExpr represents a date-time INTERVAL expression.
IntervalExpr struct {
Expr Expr
Unit string
}

// TimestampFuncExpr represents the function and arguments for TIMESTAMP{ADD,DIFF} functions.
TimestampFuncExpr struct {
Name string
Expand Down Expand Up @@ -2966,7 +2971,7 @@ type (
}

// RegexpInstrExpr represents REGEXP_INSTR()
// For more information, postVisit https://dev.mysql.com/doc/refman/8.0/en/regexp.html#function_regexp-instr
// For more information, see https://dev.mysql.com/doc/refman/8.0/en/regexp.html#function_regexp-instr
RegexpInstrExpr struct {
Expr Expr
Pattern Expr
Expand All @@ -2977,15 +2982,15 @@ type (
}

// RegexpLikeExpr represents REGEXP_LIKE()
// For more information, postVisit https://dev.mysql.com/doc/refman/8.0/en/regexp.html#function_regexp-like
// For more information, see https://dev.mysql.com/doc/refman/8.0/en/regexp.html#function_regexp-like
RegexpLikeExpr struct {
Expr Expr
Pattern Expr
MatchType Expr
}

// RegexpReplaceExpr represents REGEXP_REPLACE()
// For more information, postVisit https://dev.mysql.com/doc/refman/8.0/en/regexp.html#function_regexp-replace
// For more information, see https://dev.mysql.com/doc/refman/8.0/en/regexp.html#function_regexp-replace
RegexpReplaceExpr struct {
Expr Expr
Pattern Expr
Expand All @@ -2996,7 +3001,7 @@ type (
}

// RegexpSubstrExpr represents REGEXP_SUBSTR()
// For more information, postVisit https://dev.mysql.com/doc/refman/8.0/en/regexp.html#function_regexp-substr
// For more information, see https://dev.mysql.com/doc/refman/8.0/en/regexp.html#function_regexp-substr
RegexpSubstrExpr struct {
Expr Expr
Pattern Expr
Expand All @@ -3005,6 +3010,26 @@ type (
MatchType Expr
}

// DateAddExpr represents ADDDATE(), DATE_ADD()
// and additions with an interval on the left and right.
// For more information, see https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_date-add
DateAddExpr struct {
Type DateAddExprType
Date Expr
Unit IntervalTypes
Expr Expr
}

// DateSubExpr represents SUBDATE(), DATE_SUB()
// and subtractions with an interval on the right.
// For more information, see https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_date-sub
DateSubExpr struct {
Type DateSubExprType
Date Expr
Unit IntervalTypes
Expr Expr
}

// ArgumentLessWindowExpr stands for the following window_functions: CUME_DIST, DENSE_RANK, PERCENT_RANK, RANK, ROW_NUMBER
// These functions do not take any argument.
ArgumentLessWindowExpr struct {
Expand Down Expand Up @@ -3131,7 +3156,6 @@ func (ListArg) iExpr() {}
func (*BinaryExpr) iExpr() {}
func (*UnaryExpr) iExpr() {}
func (*IntroducerExpr) iExpr() {}
func (*IntervalExpr) iExpr() {}
func (*CollateExpr) iExpr() {}
func (*FuncExpr) iExpr() {}
func (*TimestampFuncExpr) iExpr() {}
Expand Down Expand Up @@ -3178,6 +3202,8 @@ func (*RegexpInstrExpr) iExpr() {}
func (*RegexpLikeExpr) iExpr() {}
func (*RegexpReplaceExpr) iExpr() {}
func (*RegexpSubstrExpr) iExpr() {}
func (*DateAddExpr) iExpr() {}
func (*DateSubExpr) iExpr() {}
func (*ArgumentLessWindowExpr) iExpr() {}
func (*FirstOrLastValueExpr) iExpr() {}
func (*NtileExpr) iExpr() {}
Expand Down Expand Up @@ -3269,6 +3295,8 @@ func (*RegexpInstrExpr) iCallable() {}
func (*RegexpLikeExpr) iCallable() {}
func (*RegexpReplaceExpr) iCallable() {}
func (*RegexpSubstrExpr) iCallable() {}
func (*DateAddExpr) iCallable() {}
func (*DateSubExpr) iCallable() {}
func (*ArgumentLessWindowExpr) iCallable() {}
func (*FirstOrLastValueExpr) iCallable() {}
func (*NtileExpr) iCallable() {}
Expand Down
48 changes: 34 additions & 14 deletions go/vt/sqlparser/ast_clone.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

86 changes: 60 additions & 26 deletions go/vt/sqlparser/ast_copy_on_rewrite.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 2ba1edc

Please sign in to comment.