@@ -52,7 +52,8 @@ import (
5252// remaining in the parent filter. Much of the format conversions focus
5353// on maintaining this invariant.
5454func costedIndexScans (ctx * sql.Context , a * Analyzer , n sql.Node , qFlags * sql.QueryFlags ) (sql.Node , transform.TreeIdentity , error ) {
55- return transform .Node (n , func (n sql.Node ) (sql.Node , transform.TreeIdentity , error ) {
55+ return transform .NodeWithCtx (n , nil , func (c transform.Context ) (sql.Node , transform.TreeIdentity , error ) {
56+ n := c .Node
5657 filter , ok := n .(* plan.Filter )
5758 if ! ok {
5859 return n , transform .SameTree , nil
@@ -77,7 +78,7 @@ func costedIndexScans(ctx *sql.Context, a *Analyzer, n sql.Node, qFlags *sql.Que
7778 return n , transform .SameTree , err
7879 }
7980 if ok {
80- return indexSearchableLookup (ctx , n , rt , lookup , filter .Expression , newFilter , lookupFds , qFlags )
81+ return indexSearchableLookup (ctx , c , rt , lookup , filter .Expression , newFilter , lookupFds , qFlags )
8182 } else if is .SkipIndexCosting () {
8283 return n , transform .SameTree , nil
8384 }
@@ -89,7 +90,8 @@ func costedIndexScans(ctx *sql.Context, a *Analyzer, n sql.Node, qFlags *sql.Que
8990 })
9091}
9192
92- func indexSearchableLookup (ctx * sql.Context , n sql.Node , rt sql.TableNode , lookup sql.IndexLookup , oldFilter , newFilter sql.Expression , fds * sql.FuncDepSet , qFlags * sql.QueryFlags ) (sql.Node , transform.TreeIdentity , error ) {
93+ func indexSearchableLookup (ctx * sql.Context , c transform.Context , rt sql.TableNode , lookup sql.IndexLookup , oldFilter , newFilter sql.Expression , fds * sql.FuncDepSet , qFlags * sql.QueryFlags ) (sql.Node , transform.TreeIdentity , error ) {
94+ n := c .Node
9395 if lookup .IsEmpty () {
9496 return n , transform .SameTree , nil
9597 }
@@ -115,9 +117,18 @@ func indexSearchableLookup(ctx *sql.Context, n sql.Node, rt sql.TableNode, looku
115117 }
116118
117119 if fds != nil && fds .HasMax1Row () && ! qFlags .JoinIsSet () && ! qFlags .SubqueryIsSet () && lookup .Ranges .Len () == 1 {
118- // Strict index lookup without a join or subquery scope will return
119- // at most one row. We could also use some sort of scope counting
120- // to check for single scope.
120+ // Prevent max1Row when parent will combine results
121+ if c .Parent != nil {
122+ switch parent := c .Parent .(type ) {
123+ case * plan.SetOp :
124+ return ret , transform .NewTree , nil
125+ case * plan.Project :
126+ if plan .IsUnary (parent ) {
127+ return ret , transform .NewTree , nil
128+ }
129+ }
130+ }
131+
121132 qFlags .Set (sql .QFlagMax1Row )
122133 }
123134
@@ -321,9 +332,6 @@ func getCostedIndexScan(ctx *sql.Context, statsProv sql.StatsProvider, rt sql.Ta
321332 }
322333
323334 if bestStat .FuncDeps ().HasMax1Row () && ! qFlags .JoinIsSet () && ! qFlags .SubqueryIsSet () && lookup .Ranges .Len () == 1 {
324- // Strict index lookup without a join or subquery scope will return
325- // at most one row. We could also use some sort of scope counting
326- // to check for single scope.
327335 qFlags .Set (sql .QFlagMax1Row )
328336 }
329337
0 commit comments