github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/opt/exec/execbuilder/mutation.go (about)

     1  // Copyright 2019 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  package execbuilder
    12  
    13  import (
    14  	"bytes"
    15  	"context"
    16  	"fmt"
    17  
    18  	"github.com/cockroachdb/cockroach/pkg/sql/lex"
    19  	"github.com/cockroachdb/cockroach/pkg/sql/opt"
    20  	"github.com/cockroachdb/cockroach/pkg/sql/opt/cat"
    21  	"github.com/cockroachdb/cockroach/pkg/sql/opt/exec"
    22  	"github.com/cockroachdb/cockroach/pkg/sql/opt/memo"
    23  	"github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgcode"
    24  	"github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgerror"
    25  	"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
    26  	"github.com/cockroachdb/cockroach/pkg/sql/sqlbase"
    27  	"github.com/cockroachdb/cockroach/pkg/util"
    28  	"github.com/cockroachdb/errors"
    29  )
    30  
    31  func (b *Builder) buildMutationInput(
    32  	mutExpr, inputExpr memo.RelExpr, colList opt.ColList, p *memo.MutationPrivate,
    33  ) (execPlan, error) {
    34  	if b.shouldApplyImplicitLockingToMutationInput(mutExpr) {
    35  		// Re-entrance is not possible because mutations are never nested.
    36  		b.forceForUpdateLocking = true
    37  		defer func() { b.forceForUpdateLocking = false }()
    38  	}
    39  
    40  	input, err := b.buildRelational(inputExpr)
    41  	if err != nil {
    42  		return execPlan{}, err
    43  	}
    44  
    45  	if p.WithID != 0 {
    46  		// The input might have extra columns that are used only by FK checks; make
    47  		// sure we don't project them away.
    48  		cols := inputExpr.Relational().OutputCols.Copy()
    49  		for _, c := range colList {
    50  			cols.Remove(c)
    51  		}
    52  		for c, ok := cols.Next(0); ok; c, ok = cols.Next(c + 1) {
    53  			colList = append(colList, c)
    54  		}
    55  	}
    56  
    57  	input, err = b.ensureColumns(input, colList, nil, inputExpr.ProvidedPhysical().Ordering)
    58  	if err != nil {
    59  		return execPlan{}, err
    60  	}
    61  
    62  	if p.WithID != 0 {
    63  		label := fmt.Sprintf("buffer %d", p.WithID)
    64  		bufferNode, err := b.factory.ConstructBuffer(input.root, label)
    65  		if err != nil {
    66  			return execPlan{}, err
    67  		}
    68  
    69  		b.addBuiltWithExpr(p.WithID, input.outputCols, bufferNode)
    70  		input.root = bufferNode
    71  	}
    72  	return input, nil
    73  }
    74  
    75  func (b *Builder) buildInsert(ins *memo.InsertExpr) (execPlan, error) {
    76  	if ep, ok, err := b.tryBuildFastPathInsert(ins); err != nil || ok {
    77  		return ep, err
    78  	}
    79  	// Construct list of columns that only contains columns that need to be
    80  	// inserted (e.g. delete-only mutation columns don't need to be inserted).
    81  	colList := make(opt.ColList, 0, len(ins.InsertCols)+len(ins.CheckCols)+len(ins.IndexPredicateCols))
    82  	colList = appendColsWhenPresent(colList, ins.InsertCols)
    83  	colList = appendColsWhenPresent(colList, ins.CheckCols)
    84  	colList = appendColsWhenPresent(colList, ins.IndexPredicateCols)
    85  	input, err := b.buildMutationInput(ins, ins.Input, colList, &ins.MutationPrivate)
    86  	if err != nil {
    87  		return execPlan{}, err
    88  	}
    89  
    90  	// Construct the Insert node.
    91  	tab := b.mem.Metadata().Table(ins.Table)
    92  	insertOrds := ordinalSetFromColList(ins.InsertCols)
    93  	checkOrds := ordinalSetFromColList(ins.CheckCols)
    94  	returnOrds := ordinalSetFromColList(ins.ReturnCols)
    95  	// If we planned FK checks, disable the execution code for FK checks.
    96  	disableExecFKs := !ins.FKFallback
    97  	node, err := b.factory.ConstructInsert(
    98  		input.root,
    99  		tab,
   100  		insertOrds,
   101  		returnOrds,
   102  		checkOrds,
   103  		b.allowAutoCommit && len(ins.Checks) == 0 && len(ins.FKCascades) == 0,
   104  		disableExecFKs,
   105  	)
   106  	if err != nil {
   107  		return execPlan{}, err
   108  	}
   109  	// Construct the output column map.
   110  	ep := execPlan{root: node}
   111  	if ins.NeedResults() {
   112  		ep.outputCols = mutationOutputColMap(ins)
   113  	}
   114  
   115  	if err := b.buildFKChecks(ins.Checks); err != nil {
   116  		return execPlan{}, err
   117  	}
   118  
   119  	return ep, nil
   120  }
   121  
   122  // tryBuildFastPathInsert attempts to construct an insert using the fast path,
   123  // checking all required conditions. See exec.Factory.ConstructInsertFastPath.
   124  func (b *Builder) tryBuildFastPathInsert(ins *memo.InsertExpr) (_ execPlan, ok bool, _ error) {
   125  	// If FKFallback is set, the optimizer-driven FK checks are disabled. We must
   126  	// use the legacy path.
   127  	if !b.allowInsertFastPath || ins.FKFallback {
   128  		return execPlan{}, false, nil
   129  	}
   130  
   131  	// Conditions from ConstructFastPathInsert:
   132  	//
   133  	//  - there are no other mutations in the statement, and the output of the
   134  	//    insert is not processed through side-effecting expressions (i.e. we can
   135  	//    auto-commit);
   136  	if !b.allowAutoCommit {
   137  		return execPlan{}, false, nil
   138  	}
   139  
   140  	//  - the input is Values with at most InsertFastPathMaxRows, and there are no
   141  	//    subqueries;
   142  	values, ok := ins.Input.(*memo.ValuesExpr)
   143  	if !ok || values.ChildCount() > exec.InsertFastPathMaxRows || values.Relational().HasSubquery {
   144  		return execPlan{}, false, nil
   145  	}
   146  
   147  	md := b.mem.Metadata()
   148  	tab := md.Table(ins.Table)
   149  
   150  	//  - there are no self-referencing foreign keys;
   151  	//  - all FK checks can be performed using direct lookups into unique indexes.
   152  	fkChecks := make([]exec.InsertFastPathFKCheck, len(ins.Checks))
   153  	for i := range ins.Checks {
   154  		c := &ins.Checks[i]
   155  		if md.Table(c.ReferencedTable).ID() == md.Table(ins.Table).ID() {
   156  			// Self-referencing FK.
   157  			return execPlan{}, false, nil
   158  		}
   159  		fk := tab.OutboundForeignKey(c.FKOrdinal)
   160  		lookupJoin, isLookupJoin := c.Check.(*memo.LookupJoinExpr)
   161  		if !isLookupJoin || lookupJoin.JoinType != opt.AntiJoinOp {
   162  			// Not a lookup anti-join.
   163  			return execPlan{}, false, nil
   164  		}
   165  		if len(lookupJoin.On) > 0 ||
   166  			len(lookupJoin.KeyCols) != fk.ColumnCount() {
   167  			return execPlan{}, false, nil
   168  		}
   169  		inputExpr := lookupJoin.Input
   170  		// Ignore any select (used to deal with NULLs).
   171  		if sel, isSelect := inputExpr.(*memo.SelectExpr); isSelect {
   172  			inputExpr = sel.Input
   173  		}
   174  		withScan, isWithScan := inputExpr.(*memo.WithScanExpr)
   175  		if !isWithScan {
   176  			return execPlan{}, false, nil
   177  		}
   178  		if withScan.With != ins.WithID {
   179  			return execPlan{}, false, nil
   180  		}
   181  
   182  		out := &fkChecks[i]
   183  		out.InsertCols = make([]exec.TableColumnOrdinal, len(lookupJoin.KeyCols))
   184  		findCol := func(cols opt.ColList, col opt.ColumnID) int {
   185  			res, ok := cols.Find(col)
   186  			if !ok {
   187  				panic(errors.AssertionFailedf("cannot find column %d", col))
   188  			}
   189  			return res
   190  		}
   191  		for i, keyCol := range lookupJoin.KeyCols {
   192  			// The keyCol comes from the WithScan operator. We must find the matching
   193  			// column in the mutation input.
   194  			withColOrd := findCol(withScan.OutCols, keyCol)
   195  			inputCol := withScan.InCols[withColOrd]
   196  			out.InsertCols[i] = exec.TableColumnOrdinal(findCol(ins.InsertCols, inputCol))
   197  		}
   198  
   199  		out.ReferencedTable = md.Table(lookupJoin.Table)
   200  		out.ReferencedIndex = out.ReferencedTable.Index(lookupJoin.Index)
   201  		out.MatchMethod = fk.MatchMethod()
   202  		out.MkErr = func(values tree.Datums) error {
   203  			if len(values) != len(out.InsertCols) {
   204  				return errors.AssertionFailedf("invalid FK violation values")
   205  			}
   206  			// This is a little tricky. The column ordering might not match between
   207  			// the FK reference and the index we're looking up. We have to reshuffle
   208  			// the values to fix that.
   209  			fkVals := make(tree.Datums, len(values))
   210  			for i, ordinal := range out.InsertCols {
   211  				for j := range out.InsertCols {
   212  					if fk.OriginColumnOrdinal(tab, j) == int(ordinal) {
   213  						fkVals[j] = values[i]
   214  						break
   215  					}
   216  				}
   217  			}
   218  			for i := range fkVals {
   219  				if fkVals[i] == nil {
   220  					return errors.AssertionFailedf("invalid column mapping")
   221  				}
   222  			}
   223  			return mkFKCheckErr(md, c, fkVals)
   224  		}
   225  	}
   226  
   227  	colList := make(opt.ColList, 0, len(ins.InsertCols)+len(ins.CheckCols)+len(ins.IndexPredicateCols))
   228  	colList = appendColsWhenPresent(colList, ins.InsertCols)
   229  	colList = appendColsWhenPresent(colList, ins.CheckCols)
   230  	colList = appendColsWhenPresent(colList, ins.IndexPredicateCols)
   231  	if !colList.Equals(values.Cols) {
   232  		// We have a Values input, but the columns are not in the right order. For
   233  		// example:
   234  		//   INSERT INTO ab (SELECT y, x FROM (VALUES (1, 10)) AS v (x, y))
   235  		//
   236  		// TODO(radu): we could rearrange the columns of the rows below, or add
   237  		// a normalization rule that adds a Project to rearrange the Values node
   238  		// columns.
   239  		return execPlan{}, false, nil
   240  	}
   241  
   242  	rows, err := b.buildValuesRows(values)
   243  	if err != nil {
   244  		return execPlan{}, false, err
   245  	}
   246  
   247  	// Construct the InsertFastPath node.
   248  	insertOrds := ordinalSetFromColList(ins.InsertCols)
   249  	checkOrds := ordinalSetFromColList(ins.CheckCols)
   250  	returnOrds := ordinalSetFromColList(ins.ReturnCols)
   251  	node, err := b.factory.ConstructInsertFastPath(
   252  		rows,
   253  		tab,
   254  		insertOrds,
   255  		returnOrds,
   256  		checkOrds,
   257  		fkChecks,
   258  	)
   259  	if err != nil {
   260  		return execPlan{}, false, err
   261  	}
   262  	// Construct the output column map.
   263  	ep := execPlan{root: node}
   264  	if ins.NeedResults() {
   265  		ep.outputCols = mutationOutputColMap(ins)
   266  	}
   267  	return ep, true, nil
   268  }
   269  
   270  func (b *Builder) buildUpdate(upd *memo.UpdateExpr) (execPlan, error) {
   271  	// Currently, the execution engine requires one input column for each fetch
   272  	// and update expression, so use ensureColumns to map and reorder columns so
   273  	// that they correspond to target table columns. For example:
   274  	//
   275  	//   UPDATE xyz SET x=1, y=1
   276  	//
   277  	// Here, the input has just one column (because the constant is shared), and
   278  	// so must be mapped to two separate update columns.
   279  	//
   280  	// TODO(andyk): Using ensureColumns here can result in an extra Render.
   281  	// Upgrade execution engine to not require this.
   282  	cnt := len(upd.FetchCols) + len(upd.UpdateCols) + len(upd.PassthroughCols) + len(upd.CheckCols)
   283  	colList := make(opt.ColList, 0, cnt)
   284  	colList = appendColsWhenPresent(colList, upd.FetchCols)
   285  	colList = appendColsWhenPresent(colList, upd.UpdateCols)
   286  	// The RETURNING clause of the Update can refer to the columns
   287  	// in any of the FROM tables. As a result, the Update may need
   288  	// to passthrough those columns so the projection above can use
   289  	// them.
   290  	if upd.NeedResults() {
   291  		colList = appendColsWhenPresent(colList, upd.PassthroughCols)
   292  	}
   293  	colList = appendColsWhenPresent(colList, upd.CheckCols)
   294  
   295  	input, err := b.buildMutationInput(upd, upd.Input, colList, &upd.MutationPrivate)
   296  	if err != nil {
   297  		return execPlan{}, err
   298  	}
   299  
   300  	// Construct the Update node.
   301  	md := b.mem.Metadata()
   302  	tab := md.Table(upd.Table)
   303  	fetchColOrds := ordinalSetFromColList(upd.FetchCols)
   304  	updateColOrds := ordinalSetFromColList(upd.UpdateCols)
   305  	returnColOrds := ordinalSetFromColList(upd.ReturnCols)
   306  	checkOrds := ordinalSetFromColList(upd.CheckCols)
   307  
   308  	// Construct the result columns for the passthrough set.
   309  	var passthroughCols sqlbase.ResultColumns
   310  	if upd.NeedResults() {
   311  		for _, passthroughCol := range upd.PassthroughCols {
   312  			colMeta := b.mem.Metadata().ColumnMeta(passthroughCol)
   313  			passthroughCols = append(passthroughCols, sqlbase.ResultColumn{Name: colMeta.Alias, Typ: colMeta.Type})
   314  		}
   315  	}
   316  
   317  	disableExecFKs := !upd.FKFallback
   318  	node, err := b.factory.ConstructUpdate(
   319  		input.root,
   320  		tab,
   321  		fetchColOrds,
   322  		updateColOrds,
   323  		returnColOrds,
   324  		checkOrds,
   325  		passthroughCols,
   326  		b.allowAutoCommit && len(upd.Checks) == 0 && len(upd.FKCascades) == 0,
   327  		disableExecFKs,
   328  	)
   329  	if err != nil {
   330  		return execPlan{}, err
   331  	}
   332  
   333  	if err := b.buildFKChecks(upd.Checks); err != nil {
   334  		return execPlan{}, err
   335  	}
   336  
   337  	if err := b.buildFKCascades(upd.WithID, upd.FKCascades); err != nil {
   338  		return execPlan{}, err
   339  	}
   340  
   341  	// Construct the output column map.
   342  	ep := execPlan{root: node}
   343  	if upd.NeedResults() {
   344  		ep.outputCols = mutationOutputColMap(upd)
   345  	}
   346  	return ep, nil
   347  }
   348  
   349  func (b *Builder) buildUpsert(ups *memo.UpsertExpr) (execPlan, error) {
   350  	// Currently, the execution engine requires one input column for each insert,
   351  	// fetch, and update expression, so use ensureColumns to map and reorder
   352  	// columns so that they correspond to target table columns. For example:
   353  	//
   354  	//   INSERT INTO xyz (x, y) VALUES (1, 1)
   355  	//   ON CONFLICT (x) DO UPDATE SET x=2, y=2
   356  	//
   357  	// Here, both insert values and update values come from the same input column
   358  	// (because the constants are shared), and so must be mapped to separate
   359  	// output columns.
   360  	//
   361  	// If CanaryCol = 0, then this is the "blind upsert" case, which uses a KV
   362  	// "Put" to insert new rows or blindly overwrite existing rows. Existing rows
   363  	// do not need to be fetched or separately updated (i.e. ups.FetchCols and
   364  	// ups.UpdateCols are both empty).
   365  	//
   366  	// TODO(andyk): Using ensureColumns here can result in an extra Render.
   367  	// Upgrade execution engine to not require this.
   368  	cnt := len(ups.InsertCols) + len(ups.FetchCols) + len(ups.UpdateCols) + len(ups.CheckCols) + 1
   369  	colList := make(opt.ColList, 0, cnt)
   370  	colList = appendColsWhenPresent(colList, ups.InsertCols)
   371  	colList = appendColsWhenPresent(colList, ups.FetchCols)
   372  	colList = appendColsWhenPresent(colList, ups.UpdateCols)
   373  	if ups.CanaryCol != 0 {
   374  		colList = append(colList, ups.CanaryCol)
   375  	}
   376  	colList = appendColsWhenPresent(colList, ups.CheckCols)
   377  
   378  	input, err := b.buildMutationInput(ups, ups.Input, colList, &ups.MutationPrivate)
   379  	if err != nil {
   380  		return execPlan{}, err
   381  	}
   382  
   383  	// Construct the Upsert node.
   384  	md := b.mem.Metadata()
   385  	tab := md.Table(ups.Table)
   386  	canaryCol := exec.NodeColumnOrdinal(-1)
   387  	if ups.CanaryCol != 0 {
   388  		canaryCol = input.getNodeColumnOrdinal(ups.CanaryCol)
   389  	}
   390  	insertColOrds := ordinalSetFromColList(ups.InsertCols)
   391  	fetchColOrds := ordinalSetFromColList(ups.FetchCols)
   392  	updateColOrds := ordinalSetFromColList(ups.UpdateCols)
   393  	returnColOrds := ordinalSetFromColList(ups.ReturnCols)
   394  	checkOrds := ordinalSetFromColList(ups.CheckCols)
   395  	disableExecFKs := !ups.FKFallback
   396  	node, err := b.factory.ConstructUpsert(
   397  		input.root,
   398  		tab,
   399  		canaryCol,
   400  		insertColOrds,
   401  		fetchColOrds,
   402  		updateColOrds,
   403  		returnColOrds,
   404  		checkOrds,
   405  		b.allowAutoCommit && len(ups.Checks) == 0 && len(ups.FKCascades) == 0,
   406  		disableExecFKs,
   407  	)
   408  	if err != nil {
   409  		return execPlan{}, err
   410  	}
   411  
   412  	if err := b.buildFKChecks(ups.Checks); err != nil {
   413  		return execPlan{}, err
   414  	}
   415  
   416  	// If UPSERT returns rows, they contain all non-mutation columns from the
   417  	// table, in the same order they're defined in the table. Each output column
   418  	// value is taken from an insert, fetch, or update column, depending on the
   419  	// result of the UPSERT operation for that row.
   420  	ep := execPlan{root: node}
   421  	if ups.NeedResults() {
   422  		ep.outputCols = mutationOutputColMap(ups)
   423  	}
   424  	return ep, nil
   425  }
   426  
   427  func (b *Builder) buildDelete(del *memo.DeleteExpr) (execPlan, error) {
   428  	// Check for the fast-path delete case that can use a range delete.
   429  	if ep, ok, err := b.tryBuildDeleteRange(del); err != nil || ok {
   430  		return ep, err
   431  	}
   432  
   433  	// Ensure that order of input columns matches order of target table columns.
   434  	//
   435  	// TODO(andyk): Using ensureColumns here can result in an extra Render.
   436  	// Upgrade execution engine to not require this.
   437  	colList := make(opt.ColList, 0, len(del.FetchCols))
   438  	colList = appendColsWhenPresent(colList, del.FetchCols)
   439  
   440  	input, err := b.buildMutationInput(del, del.Input, colList, &del.MutationPrivate)
   441  	if err != nil {
   442  		return execPlan{}, err
   443  	}
   444  
   445  	// Construct the Delete node.
   446  	md := b.mem.Metadata()
   447  	tab := md.Table(del.Table)
   448  	fetchColOrds := ordinalSetFromColList(del.FetchCols)
   449  	returnColOrds := ordinalSetFromColList(del.ReturnCols)
   450  	disableExecFKs := !del.FKFallback
   451  	node, err := b.factory.ConstructDelete(
   452  		input.root,
   453  		tab,
   454  		fetchColOrds,
   455  		returnColOrds,
   456  		b.allowAutoCommit && len(del.Checks) == 0 && len(del.FKCascades) == 0,
   457  		disableExecFKs,
   458  	)
   459  	if err != nil {
   460  		return execPlan{}, err
   461  	}
   462  
   463  	if err := b.buildFKChecks(del.Checks); err != nil {
   464  		return execPlan{}, err
   465  	}
   466  
   467  	if err := b.buildFKCascades(del.WithID, del.FKCascades); err != nil {
   468  		return execPlan{}, err
   469  	}
   470  
   471  	// Construct the output column map.
   472  	ep := execPlan{root: node}
   473  	if del.NeedResults() {
   474  		ep.outputCols = mutationOutputColMap(del)
   475  	}
   476  
   477  	return ep, nil
   478  }
   479  
   480  // tryBuildDeleteRange attempts to construct a fast DeleteRange execution for a
   481  // logical Delete operator, checking all required conditions. See
   482  // exec.Factory.ConstructDeleteRange.
   483  func (b *Builder) tryBuildDeleteRange(del *memo.DeleteExpr) (_ execPlan, ok bool, _ error) {
   484  	// If rows need to be returned from the Delete operator (i.e. RETURNING
   485  	// clause), no fast path is possible, because row values must be fetched.
   486  	if del.NeedResults() {
   487  		return execPlan{}, false, nil
   488  	}
   489  
   490  	// Check for simple Scan input operator without a limit; anything else is not
   491  	// supported by a range delete.
   492  	if scan, ok := del.Input.(*memo.ScanExpr); !ok || scan.HardLimit != 0 {
   493  		return execPlan{}, false, nil
   494  	}
   495  
   496  	tab := b.mem.Metadata().Table(del.Table)
   497  	if tab.DeletableIndexCount() > 1 {
   498  		// Any secondary index prevents fast path, because separate delete batches
   499  		// must be formulated to delete rows from them.
   500  		return execPlan{}, false, nil
   501  	}
   502  
   503  	primaryIdx := tab.Index(cat.PrimaryIndex)
   504  
   505  	// If the table is interleaved in another table, we cannot use the fast path.
   506  	if primaryIdx.InterleaveAncestorCount() > 0 {
   507  		return execPlan{}, false, nil
   508  	}
   509  
   510  	if primaryIdx.InterleavedByCount() > 0 {
   511  		return b.tryBuildDeleteRangeOnInterleaving(del, tab)
   512  	}
   513  
   514  	// No other tables interleaved inside this table. We can use the fast path
   515  	// if this table is not referenced by any foreign keys (because the
   516  	// integrity of those references must be checked).
   517  	if tab.InboundForeignKeyCount() > 0 {
   518  		return execPlan{}, false, nil
   519  	}
   520  
   521  	ep, err := b.buildDeleteRange(del, nil /* interleavedTables */)
   522  	if err != nil {
   523  		return execPlan{}, false, err
   524  	}
   525  	return ep, true, nil
   526  }
   527  
   528  // tryBuildDeleteRangeOnInterleaving attempts to construct a fast DeleteRange
   529  // execution for a logical Delete operator when the table is at the root of an
   530  // interleaving hierarchy.
   531  //
   532  // We can use DeleteRange only when foreign keys are set up such that a deletion
   533  // of a row cascades into deleting all interleaved rows with the same prefix.
   534  // More specifically, the following conditions must apply:
   535  //  - none of the tables in the hierarchy have secondary indexes;
   536  //  - none of the tables in the hierarchy are referenced by any tables outside
   537  //    the hierarchy;
   538  //  - all foreign key references between tables in the hierarchy have columns
   539  //    that match the interleaving;
   540  //  - all tables in the interleaving hierarchy have at least an ON DELETE
   541  //    CASCADE foreign key reference to an ancestor.
   542  //
   543  func (b *Builder) tryBuildDeleteRangeOnInterleaving(
   544  	del *memo.DeleteExpr, root cat.Table,
   545  ) (_ execPlan, ok bool, _ error) {
   546  	// To check the conditions above, we explore the entire hierarchy using
   547  	// breadth-first search.
   548  	queue := make([]cat.Table, 0, root.Index(cat.PrimaryIndex).InterleavedByCount())
   549  	tables := make(map[cat.StableID]cat.Table)
   550  	tables[root.ID()] = root
   551  	queue = append(queue, root)
   552  	for queuePos := 0; queuePos < len(queue); queuePos++ {
   553  		currTab := queue[queuePos]
   554  
   555  		if currTab.DeletableIndexCount() > 1 {
   556  			return execPlan{}, false, nil
   557  		}
   558  
   559  		currIdx := currTab.Index(cat.PrimaryIndex)
   560  		for i, n := 0, currIdx.InterleavedByCount(); i < n; i++ {
   561  			// We don't care about the index ID because we bail if any of the tables
   562  			// have any secondary indexes anyway.
   563  			tableID, _ := currIdx.InterleavedBy(i)
   564  			if tab, ok := tables[tableID]; ok {
   565  				err := errors.AssertionFailedf("multiple interleave paths to table %s", tab.Name())
   566  				return execPlan{}, false, err
   567  			}
   568  			ds, _, err := b.catalog.ResolveDataSourceByID(context.TODO(), cat.Flags{}, tableID)
   569  			if err != nil {
   570  				return execPlan{}, false, err
   571  			}
   572  			child := ds.(cat.Table)
   573  			tables[tableID] = child
   574  			queue = append(queue, child)
   575  		}
   576  	}
   577  
   578  	// Verify that there are no "inbound" foreign key references from outside the
   579  	// hierarchy and that all foreign key references between tables in the hierarchy
   580  	// match the interleaving (i.e. a prefix of the PK of the child references the
   581  	// PK of the ancestor).
   582  	for _, parent := range queue {
   583  		for i, n := 0, parent.InboundForeignKeyCount(); i < n; i++ {
   584  			fk := parent.InboundForeignKey(i)
   585  			child, ok := tables[fk.OriginTableID()]
   586  			if !ok {
   587  				// Foreign key from a table outside of the hierarchy.
   588  				return execPlan{}, false, nil
   589  			}
   590  			childIdx := child.Index(cat.PrimaryIndex)
   591  			parentIdx := parent.Index(cat.PrimaryIndex)
   592  			numCols := fk.ColumnCount()
   593  			if parentIdx.KeyColumnCount() != numCols || childIdx.KeyColumnCount() < numCols {
   594  				return execPlan{}, false, nil
   595  			}
   596  			for i := 0; i < numCols; i++ {
   597  				if fk.OriginColumnOrdinal(child, i) != childIdx.Column(i).Ordinal {
   598  					return execPlan{}, false, nil
   599  				}
   600  				if fk.ReferencedColumnOrdinal(parent, i) != parentIdx.Column(i).Ordinal {
   601  					return execPlan{}, false, nil
   602  				}
   603  			}
   604  		}
   605  	}
   606  
   607  	// Finally, verify that each table (except for the root) has an ON DELETE
   608  	// CASCADE foreign key reference to another table in the hierarchy.
   609  	for _, tab := range queue[1:] {
   610  		found := false
   611  		for i, n := 0, tab.OutboundForeignKeyCount(); i < n; i++ {
   612  			fk := tab.OutboundForeignKey(i)
   613  			if fk.DeleteReferenceAction() == tree.Cascade && tables[fk.ReferencedTableID()] != nil {
   614  				// Note that we must have already checked above that this foreign key matches
   615  				// the interleaving.
   616  				found = true
   617  				break
   618  			}
   619  		}
   620  		if !found {
   621  			return execPlan{}, false, nil
   622  		}
   623  	}
   624  
   625  	ep, err := b.buildDeleteRange(del, queue[1:])
   626  	if err != nil {
   627  		return execPlan{}, false, err
   628  	}
   629  	return ep, true, nil
   630  }
   631  
   632  // buildDeleteRange constructs a DeleteRange operator that deletes contiguous
   633  // rows in the primary index; the caller must have already checked the
   634  // conditions which allow use of DeleteRange.
   635  func (b *Builder) buildDeleteRange(
   636  	del *memo.DeleteExpr, interleavedTables []cat.Table,
   637  ) (execPlan, error) {
   638  	// tryBuildDeleteRange has already validated that input is a Scan operator.
   639  	scan := del.Input.(*memo.ScanExpr)
   640  	tab := b.mem.Metadata().Table(scan.Table)
   641  	needed, _ := b.getColumns(scan.Cols, scan.Table)
   642  	maxKeys := 0
   643  	if len(interleavedTables) == 0 {
   644  		// Calculate the maximum number of keys that the scan could return by
   645  		// multiplying the number of possible result rows by the number of column
   646  		// families of the table. The factory uses this information to determine
   647  		// whether to allow autocommit.
   648  		// We don't do this if there are interleaved children, as we don't know how
   649  		// many children rows may be in range.
   650  		maxKeys = int(b.indexConstraintMaxResults(scan)) * tab.FamilyCount()
   651  	}
   652  	// Other mutations only allow auto-commit if there are no FK checks or
   653  	// cascades. In this case, we won't actually execute anything for the checks
   654  	// or cascades - if we got this far, we determined that the FKs match the
   655  	// interleaving hierarchy and a delete range is sufficient.
   656  	root, err := b.factory.ConstructDeleteRange(
   657  		tab,
   658  		needed,
   659  		scan.Constraint,
   660  		interleavedTables,
   661  		maxKeys,
   662  		b.allowAutoCommit,
   663  	)
   664  	if err != nil {
   665  		return execPlan{}, err
   666  	}
   667  	return execPlan{root: root}, nil
   668  }
   669  
   670  // appendColsWhenPresent appends non-zero column IDs from the src list into the
   671  // dst list, and returns the possibly grown list.
   672  func appendColsWhenPresent(dst, src opt.ColList) opt.ColList {
   673  	for _, col := range src {
   674  		if col != 0 {
   675  			dst = append(dst, col)
   676  		}
   677  	}
   678  	return dst
   679  }
   680  
   681  // ordinalSetFromColList returns the set of ordinal positions of each non-zero
   682  // column ID in the given list. This is used with mutation operators, which
   683  // maintain lists that correspond to the target table, with zero column IDs
   684  // indicating columns that are not involved in the mutation.
   685  func ordinalSetFromColList(colList opt.ColList) util.FastIntSet {
   686  	var res util.FastIntSet
   687  	if colList == nil {
   688  		return res
   689  	}
   690  	for i, col := range colList {
   691  		if col != 0 {
   692  			res.Add(i)
   693  		}
   694  	}
   695  	return res
   696  }
   697  
   698  // mutationOutputColMap constructs a ColMap for the execPlan that maps from the
   699  // opt.ColumnID of each output column to the ordinal position of that column in
   700  // the result.
   701  func mutationOutputColMap(mutation memo.RelExpr) opt.ColMap {
   702  	private := mutation.Private().(*memo.MutationPrivate)
   703  	tab := mutation.Memo().Metadata().Table(private.Table)
   704  	outCols := mutation.Relational().OutputCols
   705  
   706  	var colMap opt.ColMap
   707  	ord := 0
   708  	for i, n := 0, tab.DeletableColumnCount(); i < n; i++ {
   709  		colID := private.Table.ColumnID(i)
   710  		if outCols.Contains(colID) {
   711  			colMap.Set(int(colID), ord)
   712  			ord++
   713  		}
   714  	}
   715  
   716  	// The output columns of the mutation will also include all
   717  	// columns it allowed to pass through.
   718  	for _, colID := range private.PassthroughCols {
   719  		if colID != 0 {
   720  			colMap.Set(int(colID), ord)
   721  			ord++
   722  		}
   723  	}
   724  
   725  	return colMap
   726  }
   727  
   728  func (b *Builder) buildFKChecks(checks memo.FKChecksExpr) error {
   729  	md := b.mem.Metadata()
   730  	for i := range checks {
   731  		c := &checks[i]
   732  		// Construct the query that returns FK violations.
   733  		query, err := b.buildRelational(c.Check)
   734  		if err != nil {
   735  			return err
   736  		}
   737  		// Wrap the query in an error node.
   738  		mkErr := func(row tree.Datums) error {
   739  			keyVals := make(tree.Datums, len(c.KeyCols))
   740  			for i, col := range c.KeyCols {
   741  				keyVals[i] = row[query.getNodeColumnOrdinal(col)]
   742  			}
   743  			return mkFKCheckErr(md, c, keyVals)
   744  		}
   745  		node, err := b.factory.ConstructErrorIfRows(query.root, mkErr)
   746  		if err != nil {
   747  			return err
   748  		}
   749  		b.checks = append(b.checks, node)
   750  	}
   751  	return nil
   752  }
   753  
   754  // mkFKCheckErr generates a user-friendly error describing a foreign key
   755  // violation. The keyVals are the values that correspond to the
   756  // cat.ForeignKeyConstraint columns.
   757  func mkFKCheckErr(md *opt.Metadata, c *memo.FKChecksItem, keyVals tree.Datums) error {
   758  	origin := md.TableMeta(c.OriginTable)
   759  	referenced := md.TableMeta(c.ReferencedTable)
   760  
   761  	var msg, details bytes.Buffer
   762  	if c.FKOutbound {
   763  		// Generate an error of the form:
   764  		//   ERROR:  insert on table "child" violates foreign key constraint "foo"
   765  		//   DETAIL: Key (child_p)=(2) is not present in table "parent".
   766  		fk := origin.Table.OutboundForeignKey(c.FKOrdinal)
   767  		fmt.Fprintf(&msg, "%s on table ", c.OpName)
   768  		lex.EncodeEscapedSQLIdent(&msg, string(origin.Alias.ObjectName))
   769  		msg.WriteString(" violates foreign key constraint ")
   770  		lex.EncodeEscapedSQLIdent(&msg, fk.Name())
   771  
   772  		details.WriteString("Key (")
   773  		for i := 0; i < fk.ColumnCount(); i++ {
   774  			if i > 0 {
   775  				details.WriteString(", ")
   776  			}
   777  			col := origin.Table.Column(fk.OriginColumnOrdinal(origin.Table, i))
   778  			details.WriteString(string(col.ColName()))
   779  		}
   780  		details.WriteString(")=(")
   781  		sawNull := false
   782  		for i, d := range keyVals {
   783  			if i > 0 {
   784  				details.WriteString(", ")
   785  			}
   786  			if d == tree.DNull {
   787  				// If we see a NULL, this must be a MATCH FULL failure (otherwise the
   788  				// row would have been filtered out).
   789  				sawNull = true
   790  				break
   791  			}
   792  			details.WriteString(d.String())
   793  		}
   794  		if sawNull {
   795  			details.Reset()
   796  			details.WriteString("MATCH FULL does not allow mixing of null and nonnull key values.")
   797  		} else {
   798  			details.WriteString(") is not present in table ")
   799  			lex.EncodeEscapedSQLIdent(&details, string(referenced.Alias.ObjectName))
   800  			details.WriteByte('.')
   801  		}
   802  	} else {
   803  		// Generate an error of the form:
   804  		//   ERROR:  delete on table "parent" violates foreign key constraint
   805  		//           "child_child_p_fkey" on table "child"
   806  		//   DETAIL: Key (p)=(1) is still referenced from table "child".
   807  		fk := referenced.Table.InboundForeignKey(c.FKOrdinal)
   808  		fmt.Fprintf(&msg, "%s on table ", c.OpName)
   809  		lex.EncodeEscapedSQLIdent(&msg, string(referenced.Alias.ObjectName))
   810  		msg.WriteString(" violates foreign key constraint ")
   811  		lex.EncodeEscapedSQLIdent(&msg, fk.Name())
   812  		msg.WriteString(" on table ")
   813  		lex.EncodeEscapedSQLIdent(&msg, string(origin.Alias.ObjectName))
   814  
   815  		details.WriteString("Key (")
   816  		for i := 0; i < fk.ColumnCount(); i++ {
   817  			if i > 0 {
   818  				details.WriteString(", ")
   819  			}
   820  			col := referenced.Table.Column(fk.ReferencedColumnOrdinal(referenced.Table, i))
   821  			details.WriteString(string(col.ColName()))
   822  		}
   823  		details.WriteString(")=(")
   824  		for i, d := range keyVals {
   825  			if i > 0 {
   826  				details.WriteString(", ")
   827  			}
   828  			details.WriteString(d.String())
   829  		}
   830  		details.WriteString(") is still referenced from table ")
   831  		lex.EncodeEscapedSQLIdent(&details, string(origin.Alias.ObjectName))
   832  		details.WriteByte('.')
   833  	}
   834  
   835  	return errors.WithDetail(
   836  		pgerror.Newf(pgcode.ForeignKeyViolation, "%s", msg.String()),
   837  		details.String(),
   838  	)
   839  }
   840  
   841  func (b *Builder) buildFKCascades(withID opt.WithID, cascades memo.FKCascades) error {
   842  	if len(cascades) == 0 {
   843  		return nil
   844  	}
   845  	cb, err := makeCascadeBuilder(b, withID)
   846  	if err != nil {
   847  		return err
   848  	}
   849  	for i := range cascades {
   850  		b.cascades = append(b.cascades, cb.setupCascade(&cascades[i]))
   851  	}
   852  	return nil
   853  }
   854  
   855  // canAutoCommit determines if it is safe to auto commit the mutation contained
   856  // in the expression.
   857  //
   858  // Mutations can commit the transaction as part of the same KV request,
   859  // potentially taking advantage of the 1PC optimization. This is not ok to do in
   860  // general; a sufficient set of conditions is:
   861  //   1. There is a single mutation in the query.
   862  //   2. The mutation is the root operator, or it is directly under a Project
   863  //      with no side-effecting expressions. An example of why we can't allow
   864  //      side-effecting expressions: if the projection encounters a
   865  //      division-by-zero error, the mutation shouldn't have been committed.
   866  //
   867  // An extra condition relates to how the FK checks are run. If they run before
   868  // the mutation (via the insert fast path), auto commit is possible. If they run
   869  // after the mutation (the general path), auto commit is not possible. It is up
   870  // to the builder logic for each mutation to handle this.
   871  //
   872  // Note that there are other necessary conditions related to execution
   873  // (specifically, that the transaction is implicit); it is up to the exec
   874  // factory to take that into account as well.
   875  func (b *Builder) canAutoCommit(rel memo.RelExpr) bool {
   876  	if !rel.Relational().CanMutate {
   877  		// No mutations in the expression.
   878  		return false
   879  	}
   880  
   881  	switch rel.Op() {
   882  	case opt.InsertOp, opt.UpsertOp, opt.UpdateOp, opt.DeleteOp:
   883  		// Check that there aren't any more mutations in the input.
   884  		// TODO(radu): this can go away when all mutations are under top-level
   885  		// With ops.
   886  		return !rel.Child(0).(memo.RelExpr).Relational().CanMutate
   887  
   888  	case opt.ProjectOp:
   889  		// Allow Project on top, as long as the expressions are not side-effecting.
   890  		//
   891  		// TODO(radu): for now, we only allow passthrough projections because not all
   892  		// builtins that can error out are marked as side-effecting.
   893  		proj := rel.(*memo.ProjectExpr)
   894  		if len(proj.Projections) != 0 {
   895  			return false
   896  		}
   897  		return b.canAutoCommit(proj.Input)
   898  
   899  	default:
   900  		return false
   901  	}
   902  }
   903  
   904  // forUpdateLocking is the row-level locking mode used by mutations during their
   905  // initial row scan, when such locking is deemed desirable. The locking mode is
   906  // equivalent that used by a SELECT ... FOR UPDATE statement.
   907  var forUpdateLocking = &tree.LockingItem{Strength: tree.ForUpdate}
   908  
   909  // shouldApplyImplicitLockingToMutationInput determines whether or not the
   910  // builder should apply a FOR UPDATE row-level locking mode to the initial row
   911  // scan of a mutation expression.
   912  func (b *Builder) shouldApplyImplicitLockingToMutationInput(mutExpr memo.RelExpr) bool {
   913  	switch t := mutExpr.(type) {
   914  	case *memo.InsertExpr:
   915  		// Unlike with the other three mutation expressions, it never makes
   916  		// sense to apply implicit row-level locking to the input of an INSERT
   917  		// expression because any contention results in unique constraint
   918  		// violations.
   919  		return false
   920  
   921  	case *memo.UpdateExpr:
   922  		return b.shouldApplyImplicitLockingToUpdateInput(t)
   923  
   924  	case *memo.UpsertExpr:
   925  		return b.shouldApplyImplicitLockingToUpsertInput(t)
   926  
   927  	case *memo.DeleteExpr:
   928  		return b.shouldApplyImplicitLockingToDeleteInput(t)
   929  
   930  	default:
   931  		panic(errors.AssertionFailedf("unexpected mutation expression %T", t))
   932  	}
   933  }
   934  
   935  // shouldApplyImplicitLockingToUpdateInput determines whether or not the builder
   936  // should apply a FOR UPDATE row-level locking mode to the initial row scan of
   937  // an UPDATE statement.
   938  //
   939  // Conceptually, if we picture an UPDATE statement as the composition of a
   940  // SELECT statement and an INSERT statement (with loosened semantics around
   941  // existing rows) then this method determines whether the builder should perform
   942  // the following transformation:
   943  //
   944  //   UPDATE t = SELECT FROM t + INSERT INTO t
   945  //   =>
   946  //   UPDATE t = SELECT FROM t FOR UPDATE + INSERT INTO t
   947  //
   948  // The transformation is conditional on the UPDATE expression tree matching a
   949  // pattern. Specifically, the FOR UPDATE locking mode is only used during the
   950  // initial row scan when all row filters have been pushed into the ScanExpr. If
   951  // the statement includes any filters that cannot be pushed into the scan then
   952  // no row-level locking mode is applied. The rationale here is that FOR UPDATE
   953  // locking is not necessary for correctness due to serializable isolation, so it
   954  // is strictly a performance optimization for contended writes. Therefore, it is
   955  // not worth risking the transformation being a pessimization, so it is only
   956  // applied when doing so does not risk creating artificial contention.
   957  func (b *Builder) shouldApplyImplicitLockingToUpdateInput(upd *memo.UpdateExpr) bool {
   958  	if !b.evalCtx.SessionData.ImplicitSelectForUpdate {
   959  		return false
   960  	}
   961  
   962  	// Try to match the Update's input expression against the pattern:
   963  	//
   964  	//   [Project] [IndexJoin] Scan
   965  	//
   966  	input := upd.Input
   967  	if proj, ok := input.(*memo.ProjectExpr); ok {
   968  		input = proj.Input
   969  	}
   970  	if idxJoin, ok := input.(*memo.IndexJoinExpr); ok {
   971  		input = idxJoin.Input
   972  	}
   973  	_, ok := input.(*memo.ScanExpr)
   974  	return ok
   975  }
   976  
   977  // tryApplyImplicitLockingToUpsertInput determines whether or not the builder
   978  // should apply a FOR UPDATE row-level locking mode to the initial row scan of
   979  // an UPSERT statement.
   980  //
   981  // TODO(nvanbenschoten): implement this method to match on appropriate Upsert
   982  // expression trees and apply a row-level locking mode.
   983  func (b *Builder) shouldApplyImplicitLockingToUpsertInput(ups *memo.UpsertExpr) bool {
   984  	return false
   985  }
   986  
   987  // tryApplyImplicitLockingToDeleteInput determines whether or not the builder
   988  // should apply a FOR UPDATE row-level locking mode to the initial row scan of
   989  // an DELETE statement.
   990  //
   991  // TODO(nvanbenschoten): implement this method to match on appropriate Delete
   992  // expression trees and apply a row-level locking mode.
   993  func (b *Builder) shouldApplyImplicitLockingToDeleteInput(del *memo.DeleteExpr) bool {
   994  	return false
   995  }