Skip to content

Commit cbd1c0a

Browse files
committed
norm: rule to simplify const comparison with ANY values
Given a constant value compared using the ANY or SOME operators, we check for constants in the right hand side that can be used to simplify the comparison to True. For example, the expression: 0.1 < ANY (c0, 0.4) can now be simplified since 0.1 < 0.4. Fixes #132328 Release note: None Epic: CRDB-42979
1 parent ae0b3d7 commit cbd1c0a

File tree

3 files changed

+186
-0
lines changed

3 files changed

+186
-0
lines changed

pkg/sql/opt/norm/fold_constants_funcs.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,45 @@ func (c *CustomFuncs) IsConstValueOrGroupOfConstValues(input opt.ScalarExpr) boo
193193
return memo.CanExtractConstDatum(input)
194194
}
195195

196+
// FoldComparisonWithAny evaluates a comparison expression over a constant on
197+
// the left-hand side and an ANY/SOME clause on the right-hand side.
198+
// It returns a constant expression if it finds elements in the clause
199+
// that make the comparison a definite value, and the evaluation causes
200+
// no error. Otherwise, it returns ok=false.
201+
func (c *CustomFuncs) FoldComparisonWithAny(
202+
cmp opt.Operator, left, right opt.ScalarExpr,
203+
) (_ opt.ScalarExpr, ok bool) {
204+
rightTuple := right.(*memo.TupleExpr)
205+
allConst := true
206+
hasNull := false
207+
for _, expr := range rightTuple.Elems {
208+
if !c.IsConstValueOrGroupOfConstValues(expr) {
209+
allConst = false
210+
continue
211+
}
212+
folded, ok := c.FoldComparison(cmp, left, expr)
213+
if !ok {
214+
continue
215+
}
216+
if _, ok := folded.(*memo.TrueExpr); ok {
217+
return folded, true
218+
}
219+
if _, ok := folded.(*memo.NullExpr); ok {
220+
hasNull = true
221+
}
222+
}
223+
if allConst {
224+
// In case every element in right tuple is a constant but none of them
225+
// made the comparison return TrueExpr, we can safely fold
226+
// expression to either FalseExpr or NullExpr.
227+
if hasNull {
228+
return c.f.ConstructNull(types.Bool), true
229+
}
230+
return c.f.ConstructFalse(), true
231+
}
232+
return nil, false
233+
}
234+
196235
// IsNeverNull returns true if the input is a non-null constant value,
197236
// any tuple, or any array.
198237
func (c *CustomFuncs) IsNeverNull(input opt.ScalarExpr) bool {

pkg/sql/opt/norm/rules/fold_constants.opt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,27 @@ $result
101101
=>
102102
$result
103103

104+
# FoldComparisonWithAny evaluates a comparison operation over a constant
105+
# and an ANY/SOME clause, replacing the entire expression with a constant.
106+
# It iterates over elements in the clause and tries to find constants that
107+
# make the comparison a definite value.
108+
[FoldComparisonWithAny, Normalize]
109+
(AnyScalar
110+
$left:* & (IsConstValueOrGroupOfConstValues $left)
111+
$right:* & (IsTuple $right)
112+
$cmp:* &
113+
(Let
114+
($result $ok):(FoldComparisonWithAny
115+
$cmp
116+
$left
117+
$right
118+
)
119+
$ok
120+
)
121+
)
122+
=>
123+
$result
124+
104125
# FoldComparison is similar to FoldBinary, but it involves a comparison
105126
# operation. As with FoldBinary, FoldComparison applies as long as the
106127
# evaluation would not cause an error.

pkg/sql/opt/norm/testdata/rules/fold_constants

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -788,6 +788,132 @@ values
788788
├── fd: ()-->(1)
789789
└── (false,)
790790

791+
# --------------------------------------------------
792+
# FoldComparisonWithAny
793+
# --------------------------------------------------
794+
norm expect=FoldComparisonWithAny
795+
SELECT 1 >= any(1, (select x from t limit 1))
796+
----
797+
values
798+
├── columns: "?column?":4!null
799+
├── cardinality: [1 - 1]
800+
├── key: ()
801+
├── fd: ()-->(4)
802+
└── (true,)
803+
804+
norm expect=FoldComparisonWithAny
805+
SELECT 5 > any(8, 9, 10, 11)
806+
----
807+
values
808+
├── columns: "?column?":1!null
809+
├── cardinality: [1 - 1]
810+
├── key: ()
811+
├── fd: ()-->(1)
812+
└── (false,)
813+
814+
norm expect=FoldComparisonWithAny
815+
SELECT 1 <= any(1, 2, 3, (select x from t limit 1))
816+
----
817+
values
818+
├── columns: "?column?":4!null
819+
├── cardinality: [1 - 1]
820+
├── key: ()
821+
├── fd: ()-->(4)
822+
└── (true,)
823+
824+
norm expect=FoldComparisonWithAny
825+
SELECT 10 < any(1, 2, 3, 4)
826+
----
827+
values
828+
├── columns: "?column?":1!null
829+
├── cardinality: [1 - 1]
830+
├── key: ()
831+
├── fd: ()-->(1)
832+
└── (false,)
833+
834+
norm expect=FoldComparisonWithAny
835+
SELECT 10 < any(1, 2, NULL, 4)
836+
----
837+
values
838+
├── columns: "?column?":1
839+
├── cardinality: [1 - 1]
840+
├── key: ()
841+
├── fd: ()-->(1)
842+
└── (NULL,)
843+
844+
norm expect=FoldComparisonWithAny
845+
SELECT 10 > any(1, 2, NULL, 4)
846+
----
847+
values
848+
├── columns: "?column?":1!null
849+
├── cardinality: [1 - 1]
850+
├── key: ()
851+
├── fd: ()-->(1)
852+
└── (true,)
853+
854+
norm expect=FoldComparisonWithAny
855+
SELECT 10 > any(1, 2, NULL, (select x from t limit 1))
856+
----
857+
values
858+
├── columns: "?column?":4!null
859+
├── cardinality: [1 - 1]
860+
├── key: ()
861+
├── fd: ()-->(4)
862+
└── (true,)
863+
864+
norm expect=FoldComparisonWithAny
865+
SELECT 'cockroaches' LIKE any('%bugs%', '%roaches%')
866+
----
867+
values
868+
├── columns: "?column?":1!null
869+
├── cardinality: [1 - 1]
870+
├── key: ()
871+
├── fd: ()-->(1)
872+
└── (true,)
873+
874+
norm expect=FoldComparisonWithAny
875+
SELECT 'cockroaches' LIKE any('%bugs%', '%birds%')
876+
----
877+
values
878+
├── columns: "?column?":1!null
879+
├── cardinality: [1 - 1]
880+
├── key: ()
881+
├── fd: ()-->(1)
882+
└── (false,)
883+
884+
norm expect-not=FoldComparisonWithAny
885+
SELECT 1 > any(5, 4, random()+1)
886+
----
887+
values
888+
├── columns: "?column?":1
889+
├── cardinality: [1 - 1]
890+
├── volatile
891+
├── key: ()
892+
├── fd: ()-->(1)
893+
└── (1 > ANY (5, 4, random() + 1.0),)
894+
895+
norm expect-not=FoldComparisonWithAny
896+
SELECT 1 > any(5, NULL, random()+1)
897+
----
898+
values
899+
├── columns: "?column?":1
900+
├── cardinality: [1 - 1]
901+
├── volatile
902+
├── key: ()
903+
├── fd: ()-->(1)
904+
└── (1 > ANY (5, NULL, random() + 1.0),)
905+
906+
norm expect-not=FoldComparisonWithAny
907+
SELECT 1 > any(NULL, random()+1)
908+
----
909+
values
910+
├── columns: "?column?":1
911+
├── cardinality: [1 - 1]
912+
├── volatile
913+
├── key: ()
914+
├── fd: ()-->(1)
915+
└── (1 > ANY (NULL, random() + 1.0),)
916+
791917
# --------------------------------------------------
792918
# FoldCast
793919
# --------------------------------------------------

0 commit comments

Comments
 (0)