Skip to content

Commit

Permalink
Merge #56777 #56834
Browse files Browse the repository at this point in the history
56777: opt: add insertion checks for unique constraints r=rytaft a=rytaft

This commit adds checks for unique constraints when planning insertions
in the optimizer. This does not yet impact anything outside of the optimizer
tests, since `UNIQUE WITHOUT INDEX` is still not supported outside of the
optimizer test catalog.

Informs #41535

Release note: None

56834: opt: build statistics for multi-column inverted index scans r=mgartner a=mgartner

This commit updates the statistic build so that both a `Scan.Constraint`
and `Scan.InvertedConstraint` alter the selectivity of a constrained
scan. These two fields are non-nil when the scan operates over a
multi-column inverted index.

Release note: None

Co-authored-by: Rebecca Taft <[email protected]>
Co-authored-by: Marcus Gartner <[email protected]>
  • Loading branch information
3 people committed Nov 18, 2020
3 parents a969045 + f5c3d6e + 93012d7 commit 6175638
Show file tree
Hide file tree
Showing 19 changed files with 1,541 additions and 285 deletions.
39 changes: 24 additions & 15 deletions pkg/sql/opt/exec/execbuilder/mutation.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ func (b *Builder) buildMutationInput(
}

if p.WithID != 0 {
// The input might have extra columns that are used only by FK checks; make
// sure we don't project them away.
// The input might have extra columns that are used only by FK or unique
// checks; make sure we don't project them away.
cols := inputExpr.Relational().OutputCols.Copy()
for _, c := range colList {
cols.Remove(c)
Expand Down Expand Up @@ -101,7 +101,8 @@ func (b *Builder) buildInsert(ins *memo.InsertExpr) (execPlan, error) {
insertOrds,
returnOrds,
checkOrds,
b.allowAutoCommit && len(ins.Checks) == 0 && len(ins.FKCascades) == 0,
b.allowAutoCommit && len(ins.UniqueChecks) == 0 &&
len(ins.FKChecks) == 0 && len(ins.FKCascades) == 0,
)
if err != nil {
return execPlan{}, err
Expand All @@ -112,7 +113,9 @@ func (b *Builder) buildInsert(ins *memo.InsertExpr) (execPlan, error) {
ep.outputCols = mutationOutputColMap(ins)
}

if err := b.buildFKChecks(ins.Checks); err != nil {
// TODO(rytaft): build unique checks.

if err := b.buildFKChecks(ins.FKChecks); err != nil {
return execPlan{}, err
}

Expand Down Expand Up @@ -148,9 +151,9 @@ func (b *Builder) tryBuildFastPathInsert(ins *memo.InsertExpr) (_ execPlan, ok b

// - there are no self-referencing foreign keys;
// - all FK checks can be performed using direct lookups into unique indexes.
fkChecks := make([]exec.InsertFastPathFKCheck, len(ins.Checks))
for i := range ins.Checks {
c := &ins.Checks[i]
fkChecks := make([]exec.InsertFastPathFKCheck, len(ins.FKChecks))
for i := range ins.FKChecks {
c := &ins.FKChecks[i]
if md.Table(c.ReferencedTable).ID() == md.Table(ins.Table).ID() {
// Self-referencing FK.
return execPlan{}, false, nil
Expand Down Expand Up @@ -325,13 +328,16 @@ func (b *Builder) buildUpdate(upd *memo.UpdateExpr) (execPlan, error) {
returnColOrds,
checkOrds,
passthroughCols,
b.allowAutoCommit && len(upd.Checks) == 0 && len(upd.FKCascades) == 0,
b.allowAutoCommit && len(upd.UniqueChecks) == 0 &&
len(upd.FKChecks) == 0 && len(upd.FKCascades) == 0,
)
if err != nil {
return execPlan{}, err
}

if err := b.buildFKChecks(upd.Checks); err != nil {
// TODO(rytaft): build unique checks.

if err := b.buildFKChecks(upd.FKChecks); err != nil {
return execPlan{}, err
}

Expand Down Expand Up @@ -406,13 +412,16 @@ func (b *Builder) buildUpsert(ups *memo.UpsertExpr) (execPlan, error) {
updateColOrds,
returnColOrds,
checkOrds,
b.allowAutoCommit && len(ups.Checks) == 0 && len(ups.FKCascades) == 0,
b.allowAutoCommit && len(ups.UniqueChecks) == 0 &&
len(ups.FKChecks) == 0 && len(ups.FKCascades) == 0,
)
if err != nil {
return execPlan{}, err
}

if err := b.buildFKChecks(ups.Checks); err != nil {
// TODO(rytaft): build unique checks.

if err := b.buildFKChecks(ups.FKChecks); err != nil {
return execPlan{}, err
}

Expand Down Expand Up @@ -460,13 +469,13 @@ func (b *Builder) buildDelete(del *memo.DeleteExpr) (execPlan, error) {
tab,
fetchColOrds,
returnColOrds,
b.allowAutoCommit && len(del.Checks) == 0 && len(del.FKCascades) == 0,
b.allowAutoCommit && len(del.FKChecks) == 0 && len(del.FKCascades) == 0,
)
if err != nil {
return execPlan{}, err
}

if err := b.buildFKChecks(del.Checks); err != nil {
if err := b.buildFKChecks(del.FKChecks); err != nil {
return execPlan{}, err
}

Expand Down Expand Up @@ -528,7 +537,7 @@ func (b *Builder) tryBuildDeleteRange(del *memo.DeleteExpr) (_ execPlan, ok bool
if err != nil {
return execPlan{}, false, err
}
if err := b.buildFKChecks(del.Checks); err != nil {
if err := b.buildFKChecks(del.FKChecks); err != nil {
return execPlan{}, false, err
}
if err := b.buildFKCascades(del.WithID, del.FKCascades); err != nil {
Expand Down Expand Up @@ -677,7 +686,7 @@ func (b *Builder) buildDeleteRange(
autoCommit = true
}
}
if len(del.Checks) > 0 || len(del.FKCascades) > 0 {
if len(del.FKChecks) > 0 || len(del.FKCascades) > 0 {
// Do not allow autocommit if we have checks or cascades. This does not
// apply for the interleaved case, where we decided that the delete
// range takes care of all the FKs as well.
Expand Down
18 changes: 16 additions & 2 deletions pkg/sql/opt/memo/expr_format.go
Original file line number Diff line number Diff line change
Expand Up @@ -785,7 +785,7 @@ func (f *ExprFmtCtx) formatScalarWithLabel(
f.Buffer.WriteString(": ")
}
switch scalar.Op() {
case opt.ProjectionsOp, opt.AggregationsOp, opt.FKChecksOp, opt.KVOptionsOp:
case opt.ProjectionsOp, opt.AggregationsOp, opt.UniqueChecksOp, opt.FKChecksOp, opt.KVOptionsOp:
// Omit empty lists (except filters).
if scalar.ChildCount() == 0 {
return
Expand Down Expand Up @@ -912,7 +912,8 @@ func (f *ExprFmtCtx) formatScalarWithLabel(
func (f *ExprFmtCtx) scalarPropsStrings(scalar opt.ScalarExpr) []string {
typ := scalar.DataType()
if typ == nil {
if scalar.Op() == opt.FKChecksItemOp || scalar.Op() == opt.KVOptionsItemOp {
if scalar.Op() == opt.UniqueChecksItemOp || scalar.Op() == opt.FKChecksItemOp ||
scalar.Op() == opt.KVOptionsItemOp {
// These are not true scalars and have no properties.
return nil
}
Expand Down Expand Up @@ -999,6 +1000,19 @@ func (f *ExprFmtCtx) formatScalarPrivate(scalar opt.ScalarExpr) {
case *KVOptionsItem:
fmt.Fprintf(f.Buffer, " %s", t.Key)

case *UniqueChecksItem:
tab := f.Memo.metadata.TableMeta(t.Table)
constraint := tab.Table.Unique(t.CheckOrdinal)
fmt.Fprintf(f.Buffer, ": %s(", tab.Alias.ObjectName)
for i := 0; i < constraint.ColumnCount(); i++ {
if i > 0 {
f.Buffer.WriteByte(',')
}
col := tab.Table.Column(constraint.ColumnOrdinal(tab.Table, i))
f.Buffer.WriteString(string(col.ColName()))
}
f.Buffer.WriteByte(')')

case *FKChecksItem:
origin := f.Memo.metadata.TableMeta(t.OriginTable)
referenced := f.Memo.metadata.TableMeta(t.ReferencedTable)
Expand Down
18 changes: 18 additions & 0 deletions pkg/sql/opt/memo/interner.go
Original file line number Diff line number Diff line change
Expand Up @@ -645,6 +645,12 @@ func (h *hasher) HashFKChecksExpr(val FKChecksExpr) {
}
}

func (h *hasher) HashUniqueChecksExpr(val UniqueChecksExpr) {
for i := range val {
h.HashRelExpr(val[i].Check)
}
}

func (h *hasher) HashKVOptionsExpr(val KVOptionsExpr) {
for i := range val {
h.HashString(val[i].Key)
Expand Down Expand Up @@ -1050,6 +1056,18 @@ func (h *hasher) IsFKChecksExprEqual(l, r FKChecksExpr) bool {
return true
}

func (h *hasher) IsUniqueChecksExprEqual(l, r UniqueChecksExpr) bool {
if len(l) != len(r) {
return false
}
for i := range l {
if l[i].Check != r[i].Check {
return false
}
}
return true
}

func (h *hasher) IsKVOptionsExprEqual(l, r KVOptionsExpr) bool {
if len(l) != len(r) {
return false
Expand Down
Loading

0 comments on commit 6175638

Please sign in to comment.