Skip to content

Commit 91ae9bc

Browse files
craig[bot]mgartnerrafiss
committed
51232: opt: add helper functions for partial indexes and scans r=RaduBerinde a=mgartner This commit adds helper functions to determine if indexes are partial indexes, if scans operate on partial indexes, and for retrieving partial index predicate expressions. Within the optimizer `TableMeta.PartialIndexPredicates` is now the source of truth that should be used for answering these types of questions. The catalog `Index.Predicate` function should only be used by the optbuilder. This commit also makes certain that there is an entry in the `TableMeta.PartialIndexPredicates` map for every partial index on the table, even if the partial index predicate is non-immutable. This makes the map a safe source of truth for determining which indexes are partial. Release note: None 51299: roachtest: update psycopg expected fail list r=rafiss a=rafiss Also fix the regex for parsing test results. fixes cockroachdb#51234 fixes cockroachdb#51214 fixes cockroachdb#51113 fixes cockroachdb#51051 fixes cockroachdb#51049 fixes cockroachdb#50793 Release note: None Co-authored-by: Marcus Gartner <[email protected]> Co-authored-by: Rafi Shamim <[email protected]>
3 parents d0c7962 + 43928e2 + 8bf44a8 commit 91ae9bc

File tree

7 files changed

+256
-16
lines changed

7 files changed

+256
-16
lines changed

pkg/cmd/roachtest/psycopg_blocklist.go

Lines changed: 206 additions & 1 deletion
Large diffs are not rendered by default.

pkg/cmd/roachtest/python_helpers.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import (
1717
"regexp"
1818
)
1919

20-
var pythonUnitTestOutputRegex = regexp.MustCompile(`(?P<name>.*) \((?P<class>.*)\) \.\.\. (?P<result>[^'"]*)(?: u?['"](?P<reason>.*)['"])?`)
20+
var pythonUnitTestOutputRegex = regexp.MustCompile(`(?P<name>.*) \((?P<class>.*)\) \.\.\. (?P<result>[^'"]*?)(?: u?['"](?P<reason>.*)['"])?$`)
2121

2222
func (r *ormTestsResults) parsePythonUnitTestOutput(
2323
input []byte, expectedFailures blocklist, ignoredList blocklist,
@@ -45,10 +45,10 @@ func (r *ormTestsResults) parsePythonUnitTestOutput(
4545
case expectedIgnored:
4646
r.results[test] = fmt.Sprintf("--- SKIP: %s due to %s (expected)", test, ignoredIssue)
4747
r.ignoredCount++
48-
case len(skipReason) > 0 && expectedFailure:
48+
case skipped && expectedFailure:
4949
r.results[test] = fmt.Sprintf("--- SKIP: %s due to %s (unexpected)", test, skipReason)
5050
r.unexpectedSkipCount++
51-
case len(skipReason) > 0:
51+
case skipped:
5252
r.results[test] = fmt.Sprintf("--- SKIP: %s due to %s (expected)", test, skipReason)
5353
r.skipCount++
5454
case pass && !expectedFailure:

pkg/sql/opt/memo/expr.go

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -555,11 +555,10 @@ func (s *ScanPrivate) IsCanonical() bool {
555555
// IsUnfiltered returns true if the ScanPrivate will produce all rows in the
556556
// table.
557557
func (s *ScanPrivate) IsUnfiltered(md *opt.Metadata) bool {
558-
_, isPartialIndex := md.Table(s.Table).Index(s.Index).Predicate()
559-
return !isPartialIndex &&
560-
(s.Constraint == nil || s.Constraint.IsUnconstrained()) &&
558+
return (s.Constraint == nil || s.Constraint.IsUnconstrained()) &&
561559
s.InvertedConstraint == nil &&
562-
s.HardLimit == 0
560+
s.HardLimit == 0 &&
561+
!s.UsesPartialIndex(md)
563562
}
564563

565564
// IsLocking returns true if the ScanPrivate is configured to use a row-level
@@ -570,6 +569,13 @@ func (s *ScanPrivate) IsLocking() bool {
570569
return s.Locking != nil
571570
}
572571

572+
// UsesPartialIndex returns true if the ScanPrivate indicates a scan over a
573+
// partial index.
574+
func (s *ScanPrivate) UsesPartialIndex(md *opt.Metadata) bool {
575+
tabMeta := md.TableMeta(s.Table)
576+
return IsPartialIndex(tabMeta, s.Index)
577+
}
578+
573579
// NeedResults returns true if the mutation operator can return the rows that
574580
// were mutated.
575581
func (m *MutationPrivate) NeedResults() bool {
@@ -803,6 +809,22 @@ func OutputColumnIsAlwaysNull(e RelExpr, col opt.ColumnID) bool {
803809
return false
804810
}
805811

812+
// IsPartialIndex returns true if the table's index at the given ordinal is
813+
// a partial index.
814+
func IsPartialIndex(tabMeta *opt.TableMeta, ord cat.IndexOrdinal) bool {
815+
_, isPartial := tabMeta.PartialIndexPredicates[ord]
816+
return isPartial
817+
}
818+
819+
// PartialIndexPredicate returns the FiltersExpr representing the partial index
820+
// predicate at the given index ordinal. If the index at the ordinal is not a
821+
// partial index, this function panics. IsPartialIndex should be used first to
822+
// determine if the index is a partial index.
823+
func PartialIndexPredicate(tabMeta *opt.TableMeta, ord cat.IndexOrdinal) FiltersExpr {
824+
p := tabMeta.PartialIndexPredicates[ord]
825+
return *p.(*FiltersExpr)
826+
}
827+
806828
// FKCascades stores metadata necessary for building cascading queries.
807829
type FKCascades []FKCascade
808830

pkg/sql/opt/memo/expr_format.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1220,6 +1220,7 @@ func FormatPrivate(f *ExprFmtCtx, private interface{}, physProps *physical.Requi
12201220
case *ScanPrivate:
12211221
// Don't output name of index if it's the primary index.
12221222
tab := f.Memo.metadata.Table(t.Table)
1223+
tabMeta := f.Memo.metadata.TableMeta(t.Table)
12231224
if t.Index == cat.PrimaryIndex {
12241225
fmt.Fprintf(f.Buffer, " %s", tableAlias(f, t.Table))
12251226
} else {
@@ -1228,7 +1229,7 @@ func FormatPrivate(f *ExprFmtCtx, private interface{}, physProps *physical.Requi
12281229
if ScanIsReverseFn(f.Memo.Metadata(), t, &physProps.Ordering) {
12291230
f.Buffer.WriteString(",rev")
12301231
}
1231-
if _, ok := tab.Index(t.Index).Predicate(); ok {
1232+
if IsPartialIndex(tabMeta, t.Index) {
12321233
f.Buffer.WriteString(",partial")
12331234
}
12341235

pkg/sql/opt/optbuilder/select.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -711,9 +711,21 @@ func (b *Builder) addPartialIndexPredicatesForTable(tabMeta *opt.TableMeta) {
711711
// Wrap the scalar in a FiltersItem.
712712
filter := b.factory.ConstructFiltersItem(scalar)
713713

714-
// If the expression contains non-immutable operators, do not add it to
715-
// the table metadata.
714+
// Expressions with non-immutable operators are not supported as partial
715+
// index predicates, so add a replacement expression of False. This is
716+
// done for two reasons:
717+
//
718+
// 1. TableMeta.PartialIndexPredicates is a source of truth within the
719+
// optimizer for determining which indexes are partial. It is safer
720+
// to use a False predicate than no predicate so that the optimizer
721+
// won't incorrectly assume that the index is a full index.
722+
// 2. A partial index with a False predicate will never be used to
723+
// satisfy a query, effectively making these non-immutable partial
724+
// index predicates not possible to use.
725+
//
716726
if filter.ScalarProps().VolatilitySet.HasStable() || filter.ScalarProps().VolatilitySet.HasVolatile() {
727+
fals := memo.FiltersExpr{b.factory.ConstructFiltersItem(memo.FalseSingleton)}
728+
tabMeta.AddPartialIndexPredicate(indexOrd, &fals)
717729
return
718730
}
719731

pkg/sql/opt/xform/custom_funcs.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -202,8 +202,8 @@ func (c *CustomFuncs) GeneratePartialIndexScans(
202202
// Iterate over all partial indexes.
203203
iter := makeScanIndexIter(c.e.mem, scanPrivate, rejectNonPartialIndexes)
204204
for iter.Next() {
205-
pred := tabMeta.PartialIndexPredicates[iter.IndexOrdinal()]
206-
remainingFilters, ok := c.im.FiltersImplyPredicate(filters, *pred.(*memo.FiltersExpr))
205+
pred := memo.PartialIndexPredicate(tabMeta, iter.IndexOrdinal())
206+
remainingFilters, ok := c.im.FiltersImplyPredicate(filters, pred)
207207
if !ok {
208208
// The filters do not imply the predicate, so the partial index
209209
// cannot be used.

pkg/sql/opt/xform/scan_index_iter.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,15 +144,15 @@ func (it *scanIndexIter) Next() bool {
144144
}
145145

146146
if it.hasRejectFlag(rejectPartialIndexes | rejectNonPartialIndexes) {
147-
_, ok := it.currIndex.Predicate()
147+
isPartialIndex := memo.IsPartialIndex(it.tabMeta, it.indexOrd)
148148

149149
// Skip over partial indexes if rejectPartialIndexes is set.
150-
if it.hasRejectFlag(rejectPartialIndexes) && ok {
150+
if it.hasRejectFlag(rejectPartialIndexes) && isPartialIndex {
151151
continue
152152
}
153153

154154
// Skip over non-partial indexes if rejectNonPartialIndexes is set.
155-
if it.hasRejectFlag(rejectNonPartialIndexes) && !ok {
155+
if it.hasRejectFlag(rejectNonPartialIndexes) && !isPartialIndex {
156156
continue
157157
}
158158
}

0 commit comments

Comments
 (0)