From 10e7928a83d05d6f384a078b712903df249e9c12 Mon Sep 17 00:00:00 2001 From: "vitess-bot[bot]" <108069721+vitess-bot[bot]@users.noreply.github.com> Date: Mon, 15 Jul 2024 19:25:16 -0600 Subject: [PATCH] [release-20.0] Fix Join Predicate Cleanup Bug in Route Merging (#16386) (#16390) Signed-off-by: Andres Taylor Signed-off-by: Florent Poinsard Co-authored-by: vitess-bot[bot] <108069721+vitess-bot[bot]@users.noreply.github.com> Co-authored-by: Florent Poinsard Co-authored-by: Andres Taylor --- .../endtoend/vtgate/queries/misc/misc_test.go | 11 +++++++++ .../planbuilder/operators/SQL_builder.go | 4 +++- .../planbuilder/testdata/from_cases.json | 24 +++++++++++++++++++ 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/go/test/endtoend/vtgate/queries/misc/misc_test.go b/go/test/endtoend/vtgate/queries/misc/misc_test.go index 3c031687cff..dc789f3d1bb 100644 --- a/go/test/endtoend/vtgate/queries/misc/misc_test.go +++ b/go/test/endtoend/vtgate/queries/misc/misc_test.go @@ -114,6 +114,17 @@ func TestInvalidDateTimeTimestampVals(t *testing.T) { require.Error(t, err) } +func TestJoinWithThreeTables(t *testing.T) { + utils.SkipIfBinaryIsBelowVersion(t, 20, "vtgate") + + mcmp, closer := start(t) + defer closer() + + mcmp.Exec("insert into t1(id1, id2) values (0,0), (1,1), (2,2)") + mcmp.Exec("insert into tbl(id, unq_col, nonunq_col) values (0,0,0), (1,1,1), (2,2,1)") + mcmp.Exec("select 42 from t1 u1, t1 u2, tbl u3 where u1.id1 = u2.id1 and u1.id1 = u3.id and (u1.id2 or u2.id2 or u3.unq_col)") +} + // TestIntervalWithMathFunctions tests that the Interval keyword can be used with math functions. func TestIntervalWithMathFunctions(t *testing.T) { mcmp, closer := start(t) diff --git a/go/vt/vtgate/planbuilder/operators/SQL_builder.go b/go/vt/vtgate/planbuilder/operators/SQL_builder.go index 0a2e545ea48..10faee5e568 100644 --- a/go/vt/vtgate/planbuilder/operators/SQL_builder.go +++ b/go/vt/vtgate/planbuilder/operators/SQL_builder.go @@ -233,7 +233,9 @@ func (qb *queryBuilder) joinWith(other *queryBuilder, onCondition sqlparser.Expr switch joinType { case sqlparser.NormalJoinType: newFromClause = append(stmt.GetFrom(), otherStmt.GetFrom()...) - qb.addPredicate(onCondition) + for _, pred := range sqlparser.SplitAndExpression(nil, onCondition) { + qb.addPredicate(pred) + } default: newFromClause = []sqlparser.TableExpr{buildJoin(stmt, otherStmt, onCondition, joinType)} } diff --git a/go/vt/vtgate/planbuilder/testdata/from_cases.json b/go/vt/vtgate/planbuilder/testdata/from_cases.json index 81381f3d7d7..88a4ebd7027 100644 --- a/go/vt/vtgate/planbuilder/testdata/from_cases.json +++ b/go/vt/vtgate/planbuilder/testdata/from_cases.json @@ -1783,6 +1783,30 @@ ] } }, + { + "comment": "three table join with join predicate touching all tables", + "query": "select 42 from user u join user_extra ue on u.id = ue.user_id join music m on m.user_id = u.id where u.foo or m.foo or ue.foo", + "plan": { + "QueryType": "SELECT", + "Original": "select 42 from user u join user_extra ue on u.id = ue.user_id join music m on m.user_id = u.id where u.foo or m.foo or ue.foo", + "Instructions": { + "OperatorType": "Route", + "Variant": "Scatter", + "Keyspace": { + "Name": "user", + "Sharded": true + }, + "FieldQuery": "select 42 from `user` as u, user_extra as ue, music as m where 1 != 1", + "Query": "select 42 from `user` as u, user_extra as ue, music as m where u.id = ue.user_id and m.user_id = u.id and (u.foo or m.foo or ue.foo)", + "Table": "`user`, music, user_extra" + }, + "TablesUsed": [ + "user.music", + "user.user", + "user.user_extra" + ] + } + }, { "comment": "join of normal table with information_schema", "query": "select unsharded.foo from unsharded join information_schema.CHARACTER_SETS",