Skip to content
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
12 changes: 11 additions & 1 deletion go/test/endtoend/vtgate/queries/misc/misc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func start(t *testing.T) (utils.MySQLCompare, func()) {
require.NoError(t, err)

deleteAll := func() {
tables := []string{"t1", "tbl", "unq_idx", "nonunq_idx", "tbl_enum_set", "uks.unsharded"}
tables := []string{"t1", "tbl", "unq_idx", "nonunq_idx", "tbl_enum_set", "uks.unsharded", "all_types"}
for _, table := range tables {
_, _ = mcmp.ExecAndIgnore("delete from " + table)
}
Expand Down Expand Up @@ -827,3 +827,13 @@ func TestTabletTypeRouting(t *testing.T) {
_, err = utils.ExecAllowError(t, vtConn, "select * from ks_misc.t1")
require.ErrorContains(t, err, "table unknown not found")
}

// TestJoinMixedCaseExpr tests that join condition with expression from both table having in clause is handled correctly.
func TestJoinMixedCaseExpr(t *testing.T) {
mcmp, closer := start(t)
defer closer()

mcmp.Exec(`insert into all_types(id, int_unsigned) values (1, 1), (2, 2), (3,3), (4,4), (10,5), (20, 6)`)
mcmp.Exec(`prepare prep_pk from 'SELECT t1.id from all_types t1 join all_types t2 on t1.int_unsigned = (case when t2.int_unsigned in (1, 2, 3) then 1 when t2.int_unsigned = 4 then 10 else 20 end)'`)
mcmp.AssertMatches(`execute prep_pk`, `[[INT64(1)] [INT64(1)] [INT64(1)]]`)
}
16 changes: 15 additions & 1 deletion go/vt/vtgate/evalengine/translate_simplify.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,10 +138,24 @@ func simplifyExpr(env *ExpressionEnv, e IR) (IR, error) {
if err != nil {
return nil, err
}
return &Literal{inner: simplified}, nil
return evalToIR(simplified), nil
}
if err := e.simplify(env); err != nil {
return nil, err
}
return e, nil
}

// evalToIR turns an internal eval result into an IR:
// - if it’s an evalTuple, it recurses into a TupleExpr
// - otherwise it wraps the single value in a Literal
func evalToIR(simplified eval) IR {
if tuple, isTuple := simplified.(*evalTuple); isTuple {
te := make(TupleExpr, len(tuple.t))
for i, t := range tuple.t {
te[i] = evalToIR(t)
}
return te
}
return &Literal{inner: simplified}
}
42 changes: 42 additions & 0 deletions go/vt/vtgate/planbuilder/testdata/from_cases.json
Original file line number Diff line number Diff line change
Expand Up @@ -4761,5 +4761,47 @@
"user.user_extra"
]
}
},
{
"comment": "case statement in join condition for evaluation - tuple‐expr simplification in CASE",
"query": "select 1 from user u1 join user u2 on u1.col = (case when u2.col = 2 then 0 when u2.col in (1, 2) then 1 else 2 end)",
"plan": {
"Type": "Join",
"QueryType": "SELECT",
"Original": "select 1 from user u1 join user u2 on u1.col = (case when u2.col = 2 then 0 when u2.col in (1, 2) then 1 else 2 end)",
"Instructions": {
"OperatorType": "Join",
"Variant": "Join",
"JoinColumnIndexes": "L:0",
"JoinVars": {
"u1_col": 1
},
"Inputs": [
{
"OperatorType": "Route",
"Variant": "Scatter",
"Keyspace": {
"Name": "user",
"Sharded": true
},
"FieldQuery": "select 1, u1.col from `user` as u1 where 1 != 1",
"Query": "select 1, u1.col from `user` as u1"
},
{
"OperatorType": "Route",
"Variant": "Scatter",
"Keyspace": {
"Name": "user",
"Sharded": true
},
"FieldQuery": "select 1 from `user` as u2 where 1 != 1",
"Query": "select 1 from `user` as u2 where :u1_col /* INT16 */ = case when u2.col = 2 then 0 when u2.col in (1, 2) then 1 else 2 end"
}
]
},
"TablesUsed": [
"user.user"
]
}
}
]
Loading