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

Enhanced output for vexplain keys #16892

Merged
merged 6 commits into from
Oct 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 123 additions & 0 deletions go/vt/sqlparser/ast_funcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -517,6 +517,70 @@ func (node *ComparisonExpr) IsImpossible() bool {
return false
}

func (op ComparisonExprOperator) Inverse() ComparisonExprOperator {
switch op {
case EqualOp:
return NotEqualOp
case LessThanOp:
return GreaterEqualOp
case GreaterThanOp:
return LessEqualOp
case LessEqualOp:
return GreaterThanOp
case GreaterEqualOp:
return LessThanOp
case NotEqualOp:
return EqualOp
case NullSafeEqualOp:
return NotEqualOp
case InOp:
return NotInOp
case NotInOp:
return InOp
case LikeOp:
return NotLikeOp
case NotLikeOp:
return LikeOp
case RegexpOp:
return NotRegexpOp
case NotRegexpOp:
return RegexpOp
}
panic("unreachable")
}

// SwitchSides returns the reversed comparison operator if applicable, along with a boolean indicating success.
// For symmetric operators like '=', '!=', and '<=>', it returns the same operator and true.
// For directional comparison operators ('<', '>', '<=', '>='), it returns the opposite operator and true.
// For operators that imply directionality or cannot be logically reversed (such as 'IN', 'LIKE', 'REGEXP'),
// it returns the original operator and false, indicating that switching sides is not valid.
func (op ComparisonExprOperator) SwitchSides() (ComparisonExprOperator, bool) {
switch op {
case EqualOp, NotEqualOp, NullSafeEqualOp:
// These operators are symmetric, so switching sides has no effect
return op, true
case LessThanOp:
return GreaterThanOp, true
case GreaterThanOp:
return LessThanOp, true
case LessEqualOp:
return GreaterEqualOp, true
case GreaterEqualOp:
return LessEqualOp, true
default:
return op, false
}
}

func (op ComparisonExprOperator) IsCommutative() bool {
switch op {
case EqualOp, NotEqualOp, NullSafeEqualOp:
return true
default:
return false
}
}

// NewStrLiteral builds a new StrVal.
func NewStrLiteral(in string) *Literal {
return &Literal{Type: StrVal, Val: in}
Expand Down Expand Up @@ -1498,6 +1562,65 @@ func (op ComparisonExprOperator) ToString() string {
}
}

func ComparisonExprOperatorFromJson(s string) ComparisonExprOperator {
switch s {
case EqualStr:
return EqualOp
case JsonLessThanStr:
return LessThanOp
case JsonGreaterThanStr:
return GreaterThanOp
case JsonLessThanOrEqualStr:
return LessEqualOp
case JsonGreaterThanOrEqualStr:
return GreaterEqualOp
case NotEqualStr:
return NotEqualOp
case NullSafeEqualStr:
return NullSafeEqualOp
case InStr:
return InOp
case NotInStr:
return NotInOp
case LikeStr:
return LikeOp
case NotLikeStr:
return NotLikeOp
case RegexpStr:
return RegexpOp
case NotRegexpStr:
return NotRegexpOp
default:
return 0
}
}

const (
JsonGreaterThanStr = "gt"
JsonLessThanStr = "lt"
JsonGreaterThanOrEqualStr = "ge"
JsonLessThanOrEqualStr = "le"
)

// JSONString returns a string representation for this operator that does not need escaping in JSON
func (op ComparisonExprOperator) JSONString() string {
switch op {
case EqualOp, NotEqualOp, NullSafeEqualOp, InOp, NotInOp, LikeOp, NotLikeOp, RegexpOp, NotRegexpOp:
// These operators are safe for JSON output, so we delegate to ToString
return op.ToString()
case LessThanOp:
return JsonLessThanStr
case GreaterThanOp:
return JsonGreaterThanStr
case LessEqualOp:
return JsonLessThanOrEqualStr
case GreaterEqualOp:
return JsonGreaterThanOrEqualStr
default:
panic("unreachable")
}
}

// ToString returns the operator as a string
func (op IsExprOperator) ToString() string {
switch op {
Expand Down
41 changes: 0 additions & 41 deletions go/vt/sqlparser/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -692,47 +692,6 @@ const (
All
)

func (op ComparisonExprOperator) Inverse() ComparisonExprOperator {
switch op {
case EqualOp:
return NotEqualOp
case LessThanOp:
return GreaterEqualOp
case GreaterThanOp:
return LessEqualOp
case LessEqualOp:
return GreaterThanOp
case GreaterEqualOp:
return LessThanOp
case NotEqualOp:
return EqualOp
case NullSafeEqualOp:
return NotEqualOp
case InOp:
return NotInOp
case NotInOp:
return InOp
case LikeOp:
return NotLikeOp
case NotLikeOp:
return LikeOp
case RegexpOp:
return NotRegexpOp
case NotRegexpOp:
return RegexpOp
}
panic("unreachable")
}

func (op ComparisonExprOperator) IsCommutative() bool {
switch op {
case EqualOp, NotEqualOp, NullSafeEqualOp:
return true
default:
return false
}
}

// Constant for Enum Type - IsExprOperator
const (
IsNullOp IsExprOperator = iota
Expand Down
84 changes: 54 additions & 30 deletions go/vt/vtgate/executor_vexplain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,54 +122,61 @@ func TestVExplainKeys(t *testing.T) {
{
query: "select count(*), col2 from music group by col2",
expectedRowString: `{
"statementType": "SELECT",
"groupingColumns": [
"music.col2"
],
"statementType": "SELECT"
"selectColumns": [
"music.col2"
]
}`,
}, {
query: "select * from user u join user_extra ue on u.id = ue.user_id where u.col1 > 100 and ue.noLimit = 'foo'",
expectedRowString: `{
"statementType": "SELECT",
"joinColumns": [
"user.id",
"user_extra.user_id"
"user.id =",
"user_extra.user_id ="
],
"filterColumns": [
"user.col1",
"user_extra.noLimit"
],
"statementType": "SELECT"
"user.col1 gt",
"user_extra.noLimit ="
]
}`,
}, {
// same as above, but written differently
query: "select * from user_extra ue, user u where ue.noLimit = 'foo' and u.col1 > 100 and ue.user_id = u.id",
expectedRowString: `{
"statementType": "SELECT",
"joinColumns": [
"user.id",
"user_extra.user_id"
"user.id =",
"user_extra.user_id ="
],
"filterColumns": [
"user.col1",
"user_extra.noLimit"
],
"statementType": "SELECT"
"user.col1 gt",
"user_extra.noLimit ="
]
}`,
},
{
query: "select u.foo, ue.bar, count(*) from user u join user_extra ue on u.id = ue.user_id where u.name = 'John Doe' group by 1, 2",
expectedRowString: `{
"statementType": "SELECT",
"groupingColumns": [
"user.foo",
"user_extra.bar"
],
"joinColumns": [
"user.id",
"user_extra.user_id"
"user.id =",
"user_extra.user_id ="
],
"filterColumns": [
"user.name"
"user.name ="
],
"statementType": "SELECT"
"selectColumns": [
"user.foo",
"user_extra.bar"
]
}`,
},
{
Expand All @@ -181,47 +188,64 @@ func TestVExplainKeys(t *testing.T) {
{
query: "select name, sum(amount) from user group by name",
expectedRowString: `{
"statementType": "SELECT",
"groupingColumns": [
"user.name"
],
"statementType": "SELECT"
"selectColumns": [
"user.amount",
"user.name"
]
}`,
},
{
query: "select name from user where age > 30",
expectedRowString: `{
"statementType": "SELECT",
"filterColumns": [
"user.age"
"user.age gt"
],
"statementType": "SELECT"
"selectColumns": [
"user.name"
]
}`,
},
{
query: "select * from user where name = 'apa' union select * from user_extra where name = 'monkey'",
expectedRowString: `{
"statementType": "SELECT",
"filterColumns": [
"user.name",
"user_extra.name"
],
"statementType": "SELECT"
"user.name =",
"user_extra.name ="
]
}`,
},
{
query: "update user set name = 'Jane Doe' where id = 1",
expectedRowString: `{
"statementType": "UPDATE",
"filterColumns": [
"user.id"
],
"statementType": "UPDATE"
"user.id ="
]
}`,
},
{
query: "delete from user where order_date < '2023-01-01'",
expectedRowString: `{
"statementType": "DELETE",
"filterColumns": [
"user.order_date"
],
"statementType": "DELETE"
"user.order_date lt"
]
}`,
},
{
query: "select * from user where name between 'A' and 'C'",
expectedRowString: `{
"statementType": "SELECT",
"filterColumns": [
"user.name ge",
"user.name le"
]
}`,
},
}
Expand Down
Loading
Loading