-
Notifications
You must be signed in to change notification settings - Fork 3.8k
/
Copy pathconstraint.go
130 lines (113 loc) · 4.13 KB
/
constraint.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// Copyright 2022 The Cockroach Authors.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.
package sql
import (
"context"
"github.com/cockroachdb/cockroach/pkg/roachpb"
"github.com/cockroachdb/cockroach/pkg/sql/catalog"
"github.com/cockroachdb/cockroach/pkg/sql/catalog/descpb"
"github.com/cockroachdb/cockroach/pkg/sql/opt"
"github.com/cockroachdb/cockroach/pkg/sql/opt/idxconstraint"
"github.com/cockroachdb/cockroach/pkg/sql/opt/memo"
"github.com/cockroachdb/cockroach/pkg/sql/opt/norm"
"github.com/cockroachdb/cockroach/pkg/sql/opt/optbuilder"
"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
"github.com/cockroachdb/cockroach/pkg/sql/span"
"github.com/cockroachdb/cockroach/pkg/sql/types"
"github.com/cockroachdb/errors"
)
// SpanConstrainer is an interface for constraining spans.
type SpanConstrainer interface {
// ConstrainPrimaryIndexSpanByExpr constrains primary index span using specified filter expression.
// Returns constrained spans that fully satisfy the expression.
// If the expression cannot be fully satisfied, returns an error.
// Expression is required to specify constraints over unqualified primary key columns only.
// The expression must evaluate to a boolean value.
// If the expression is a contradiction, returns an error.
ConstrainPrimaryIndexSpanByExpr(
ctx context.Context,
desc catalog.TableDescriptor,
evalCtx *tree.EvalContext,
semaCtx *tree.SemaContext,
filter tree.Expr,
) ([]roachpb.Span, error)
}
// ConstrainPrimaryIndexSpanByExpr implements SpanConstrainer
func (p *planner) ConstrainPrimaryIndexSpanByExpr(
ctx context.Context,
desc catalog.TableDescriptor,
evalCtx *tree.EvalContext,
semaCtx *tree.SemaContext,
filter tree.Expr,
) ([]roachpb.Span, error) {
var oc optCatalog
oc.init(p)
oc.reset()
tbl, err := newOptTable(desc, oc.codec(), nil /*stats */, emptyZoneConfig)
if err != nil {
return nil, err
}
var nf norm.Factory
nf.Init(evalCtx, &oc)
nf.Metadata().AddTable(tbl, &tree.TableName{})
b := optbuilder.NewScalar(ctx, semaCtx, evalCtx, &nf)
if err := b.Build(filter); err != nil {
return nil, err
}
root := nf.Memo().RootExpr().(opt.ScalarExpr)
if root.DataType() != types.Bool {
return nil, errors.AssertionFailedf(
"expected boolean expression, found expression of type %s", root.DataType())
}
fe := memo.FiltersExpr{nf.ConstructFiltersItem(root)}
fe = nf.CustomFuncs().SimplifyFilters(fe)
fe = nf.CustomFuncs().ConsolidateFilters(fe)
if fe.IsTrue() {
return []roachpb.Span{desc.PrimaryIndexSpan(oc.codec())}, nil
}
if fe.IsFalse() {
return nil, errors.Newf("filter %q is a contradiction", filter)
}
primary := desc.GetPrimaryIndex()
indexCols := make([]opt.OrderingColumn, len(primary.IndexDesc().KeyColumnIDs))
var notNullIndexCols opt.ColSet
for i, colID := range primary.IndexDesc().KeyColumnIDs {
indexCols[i] = opt.OrderingColumn(colID)
if primary.GetKeyColumnDirection(i) == descpb.IndexDescriptor_ASC {
indexCols[i] = opt.OrderingColumn(colID)
} else {
indexCols[i] = opt.OrderingColumn(-colID)
}
notNullIndexCols.Add(opt.ColumnID(colID))
}
const consolidate = true
var ic idxconstraint.Instance
ic.Init(
fe, nil, indexCols, notNullIndexCols, nil,
consolidate, evalCtx, &nf, nil,
)
if ic.Constraint().IsContradiction() {
return nil, errors.Newf("filter %q is a contradiction", filter)
}
if !ic.RemainingFilters().IsTrue() {
err = errors.Newf(
"primary key span %s cannot be fully constrained by expression %q",
desc.PrimaryIndexSpan(oc.codec()), filter)
if len(indexCols) > 1 {
// Constraints over composite keys are hard. Give a bit of a hint.
err = errors.WithHint(err,
"try constraining prefix columns of the composite key with equality or an IN clause")
}
return nil, err
}
var sb span.Builder
sb.Init(evalCtx, oc.codec(), desc, desc.GetPrimaryIndex())
return sb.SpansFromConstraint(ic.Constraint(), span.NoopSplitter())
}