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 }