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

     1  // Copyright 2018 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 optbuilder
    12  
    13  import (
    14  	"github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgcode"
    15  	"github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgerror"
    16  	"github.com/cockroachdb/cockroach/pkg/sql/privilege"
    17  	"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
    18  )
    19  
    20  // buildDelete builds a memo group for a DeleteOp expression, which deletes all
    21  // rows projected by the input expression. All columns from the deletion table
    22  // are projected, including mutation columns (the optimizer may later prune the
    23  // columns if they are not needed).
    24  //
    25  // Note that the ORDER BY clause can only be used if the LIMIT clause is also
    26  // present. In that case, the ordering determines which rows are included by the
    27  // limit. The ORDER BY makes no additional guarantees about the order in which
    28  // mutations are applied, or the order of any returned rows (i.e. it won't
    29  // become a physical property required of the Delete operator).
    30  func (b *Builder) buildDelete(del *tree.Delete, inScope *scope) (outScope *scope) {
    31  	// UX friendliness safeguard.
    32  	if del.Where == nil && b.evalCtx.SessionData.SafeUpdates {
    33  		panic(pgerror.DangerousStatementf("DELETE without WHERE clause"))
    34  	}
    35  
    36  	if del.OrderBy != nil && del.Limit == nil {
    37  		panic(pgerror.Newf(pgcode.Syntax,
    38  			"DELETE statement requires LIMIT when ORDER BY is used"))
    39  	}
    40  
    41  	// Find which table we're working on, check the permissions.
    42  	tab, depName, alias, refColumns := b.resolveTableForMutation(del.Table, privilege.DELETE)
    43  
    44  	if refColumns != nil {
    45  		panic(pgerror.Newf(pgcode.Syntax,
    46  			"cannot specify a list of column IDs with DELETE"))
    47  	}
    48  
    49  	// Check Select permission as well, since existing values must be read.
    50  	b.checkPrivilege(depName, tab, privilege.SELECT)
    51  
    52  	var mb mutationBuilder
    53  	mb.init(b, "delete", tab, alias)
    54  
    55  	// Build the input expression that selects the rows that will be deleted:
    56  	//
    57  	//   WITH <with>
    58  	//   SELECT <cols> FROM <table> WHERE <where>
    59  	//   ORDER BY <order-by> LIMIT <limit>
    60  	//
    61  	// All columns from the delete table will be projected.
    62  	mb.buildInputForDelete(inScope, del.Table, del.Where, del.Limit, del.OrderBy)
    63  
    64  	// Build the final delete statement, including any returned expressions.
    65  	if resultsNeeded(del.Returning) {
    66  		mb.buildDelete(*del.Returning.(*tree.ReturningExprs))
    67  	} else {
    68  		mb.buildDelete(nil /* returning */)
    69  	}
    70  
    71  	return mb.outScope
    72  }
    73  
    74  // buildDelete constructs a Delete operator, possibly wrapped by a Project
    75  // operator that corresponds to the given RETURNING clause.
    76  func (mb *mutationBuilder) buildDelete(returning tree.ReturningExprs) {
    77  	mb.buildFKChecksAndCascadesForDelete()
    78  
    79  	private := mb.makeMutationPrivate(returning != nil)
    80  	mb.outScope.expr = mb.b.factory.ConstructDelete(mb.outScope.expr, mb.checks, private)
    81  
    82  	mb.buildReturning(returning)
    83  }