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 }