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
44 changes: 44 additions & 0 deletions enginetest/queries/join_queries.go
Original file line number Diff line number Diff line change
Expand Up @@ -1342,6 +1342,50 @@ var JoinScriptTests = []ScriptTest{
},
},
},
{
// https://github.com/dolthub/dolt/issues/10304
Name: "3-way join with 1 primary key table, 2 keyless tables, and join filter on keyless tables",
SetUpScript: []string{
"CREATE TABLE t0(c0 VARCHAR(500), c1 INT);",
"CREATE TABLE t6(t6c0 VARCHAR(500), t6c1 INT, PRIMARY KEY(t6c0));",
"CREATE VIEW v0(c0) AS SELECT t0.c1 FROM t0;",
"create table t1(c0 int)",
"INSERT INTO t6(t6c0) VALUES (3);",
"INSERT INTO t6(t6c0, t6c1) VALUES (2, '-1'), ('', '1');",
"INSERT INTO t6(t6c0, t6c1) VALUES (true, 0);",
"INSERT INTO t0(c0, c1) VALUES (-1, false);",
"INSERT INTO t0(c1) VALUES (-7);",
"insert into t1(c0) values (-7),(0)",
},
Assertions: []ScriptTestAssertion{
{
Query: "SELECT * FROM t6, t1 INNER JOIN t0 ON ((t1.c0)<=>(t0.c1));",
Expected: []sql.Row{
{"", 1, -7, nil, -7},
{"", 1, 0, "-1", 0},
{"1", 0, -7, nil, -7},
{"1", 0, 0, "-1", 0},
{"2", -1, -7, nil, -7},
{"2", -1, 0, "-1", 0},
{"3", nil, -7, nil, -7},
{"3", nil, 0, "-1", 0},
},
},
{
Query: "SELECT * FROM t6, v0 INNER JOIN t0 ON ((v0.c0)<=>(t0.c1));",
Expected: []sql.Row{
{"", 1, -7, nil, -7},
{"", 1, 0, "-1", 0},
{"1", 0, -7, nil, -7},
{"1", 0, 0, "-1", 0},
{"2", -1, -7, nil, -7},
{"2", -1, 0, "-1", 0},
{"3", nil, -7, nil, -7},
{"3", nil, 0, "-1", 0},
},
},
},
},
}

var LateralJoinScriptTests = []ScriptTest{
Expand Down
26 changes: 9 additions & 17 deletions sql/memo/join_order_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ func (j *joinOrderBuilder) buildSingleLookupPlan() bool {
fds := j.m.root.RelProps.FuncDeps()
fdKey, hasKey := fds.StrictKey()
// fdKey is a set of columns which constrain all other columns in the join.
// If a chain of lookups exist, then the columns in fdKey must be in the innermost join.
// If a chain of lookups exists, then the columns in fdKey must be in the innermost join.
if !hasKey {
return false
}
Expand Down Expand Up @@ -324,22 +324,14 @@ func (j *joinOrderBuilder) buildSingleLookupPlan() bool {
}
}

if len(joinCandidates) > 1 {
// We end up here if there are multiple possible choices for the next join.
// This could happen if there are redundant rules. For now, we bail out if this happens.
return false
}

if len(joinCandidates) == 0 {
// There are still tables left to join, but no more filters that match the already joined tables.
// This can happen, for instance, if the remaining table is a single-row table that was cross-joined.
// It's probably safe to just join the remaining tables here.
remainingVertexes := j.allVertices().difference(currentlyJoinedVertexes)
for idx, ok := remainingVertexes.next(0); ok; idx, ok = remainingVertexes.next(idx + 1) {
nextVertex := newBitSet(idx)
j.addJoin(plan.JoinTypeCross, currentlyJoinedVertexes, nextVertex, nil, nil, false)
currentlyJoinedVertexes = currentlyJoinedVertexes.union(nextVertex)
}
if len(joinCandidates) != 1 {
// For now, we bail out if there are no or multiple possible choices for the next join.
// There are no possible choices for the next join when the filters are not applicable to the table
// containing the functional dependency key. Suppose we have a query like
// `select from A, B, inner join C on B.c0 <=> C.c0` where table A has a primary key and tables B and C are
// keyless; in this case, keyColumn would match table A's primary key, currentlyJoinedTables would only
// contain table A, and the join filter for tables B and C would not apply.
// There are multiple possible choices for the next join if there are redundant rules.
return false
}

Expand Down