diff --git a/enginetest/queries/script_queries.go b/enginetest/queries/script_queries.go index f11d7ac2cd..387449357d 100644 --- a/enginetest/queries/script_queries.go +++ b/enginetest/queries/script_queries.go @@ -13439,6 +13439,20 @@ select * from t1 except ( }, }, }, + { + // https://github.com/dolthub/dolt/issues/10070 + Name: "NOT EXISTS with nullable filter", + SetUpScript: []string{ + "CREATE TABLE t0(c0 INT , c1 INT);", + "INSERT INTO t0(c0, c1) VALUES (1, -2);", + }, + Assertions: []ScriptTestAssertion{ + { + Query: `SELECT * FROM t0 WHERE NOT EXISTS (SELECT 1 FROM (SELECT 1) alias0 WHERE (CASE -1 WHEN t0.c1 THEN false END));`, + Expected: []sql.Row{{1, -2}}, + }, + }, + }, } var SpatialScriptTests = []ScriptTest{ diff --git a/sql/analyzer/hoist_filters.go b/sql/analyzer/hoist_filters.go index 6375f6697e..d81a131a5b 100644 --- a/sql/analyzer/hoist_filters.go +++ b/sql/analyzer/hoist_filters.go @@ -131,7 +131,13 @@ func recurseSubqueryForOuterFilters(n sql.Node, a *Analyzer, corr sql.ColSet) (s newCorr = newCorr.Union(outOfScope) keepFilters = append(keepFilters, e) } else { - // nothing tethers the subquery to this scope + // nothing tethers the subquery or filter expression to this scope + if sq == nil && e.IsNullable() { + // If a filter expression has been hoisted out of a subquery, it needs to be made not nullable. This + // is because filters that evaluate to null in an Exists or In subquery are treated the same as + // false. + e = expression.NewIsTrue(e) + } hoistFilters = append(hoistFilters, e) } }